13434Sesaxe /* 23434Sesaxe * CDDL HEADER START 33434Sesaxe * 43434Sesaxe * The contents of this file are subject to the terms of the 53434Sesaxe * Common Development and Distribution License (the "License"). 63434Sesaxe * You may not use this file except in compliance with the License. 73434Sesaxe * 83434Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93434Sesaxe * or http://www.opensolaris.org/os/licensing. 103434Sesaxe * See the License for the specific language governing permissions 113434Sesaxe * and limitations under the License. 123434Sesaxe * 133434Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 143434Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153434Sesaxe * If applicable, add the following below this CDDL HEADER, with the 163434Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 173434Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 183434Sesaxe * 193434Sesaxe * CDDL HEADER END 203434Sesaxe */ 213434Sesaxe /* 223434Sesaxe * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233434Sesaxe * Use is subject to license terms. 243434Sesaxe */ 253434Sesaxe 263434Sesaxe #pragma ident "%Z%%M% %I% %E% SMI" 273434Sesaxe 283434Sesaxe #include <sys/systm.h> 293434Sesaxe #include <sys/types.h> 303434Sesaxe #include <sys/param.h> 313434Sesaxe #include <sys/thread.h> 323434Sesaxe #include <sys/cpuvar.h> 333434Sesaxe #include <sys/cpupart.h> 343434Sesaxe #include <sys/kmem.h> 353434Sesaxe #include <sys/cmn_err.h> 363434Sesaxe #include <sys/kstat.h> 373434Sesaxe #include <sys/processor.h> 383434Sesaxe #include <sys/disp.h> 393434Sesaxe #include <sys/group.h> 403434Sesaxe #include <sys/pg.h> 413434Sesaxe 423434Sesaxe /* 433434Sesaxe * Processor groups 443434Sesaxe * 453434Sesaxe * With the introduction of Chip Multi-Threaded (CMT) processor architectures, 463434Sesaxe * it is no longer necessarily true that a given physical processor module 473434Sesaxe * will present itself as a single schedulable entity (cpu_t). Rather, each 483434Sesaxe * chip and/or processor core may present itself as one or more "logical" CPUs. 493434Sesaxe * 503434Sesaxe * The logical CPUs presented may share physical components such as caches, 513434Sesaxe * data pipes, execution pipelines, FPUs, etc. It is advantageous to have the 523434Sesaxe * kernel be aware of the relationships existing between logical CPUs so that 533434Sesaxe * the appropriate optmizations may be employed. 543434Sesaxe * 553434Sesaxe * The processor group abstraction represents a set of logical CPUs that 563434Sesaxe * generally share some sort of physical or characteristic relationship. 573434Sesaxe * 583434Sesaxe * In the case of a physical sharing relationship, the CPUs in the group may 593434Sesaxe * share a pipeline, cache or floating point unit. In the case of a logical 603434Sesaxe * relationship, a PG may represent the set of CPUs in a processor set, or the 613434Sesaxe * set of CPUs running at a particular clock speed. 623434Sesaxe * 633434Sesaxe * The generic processor group structure, pg_t, contains the elements generic 643434Sesaxe * to a group of CPUs. Depending on the nature of the CPU relationship 653434Sesaxe * (LOGICAL or PHYSICAL), a pointer to a pg may be recast to a "view" of that 663434Sesaxe * PG where more specific data is represented. 673434Sesaxe * 683434Sesaxe * As an example, a PG representing a PHYSICAL relationship, may be recast to 693434Sesaxe * a pghw_t, where data further describing the hardware sharing relationship 703434Sesaxe * is maintained. See pghw.c and pghw.h for details on physical PGs. 713434Sesaxe * 723434Sesaxe * At this time a more specialized casting of a PG representing a LOGICAL 733434Sesaxe * relationship has not been implemented, but the architecture allows for this 743434Sesaxe * in the future. 753434Sesaxe * 763434Sesaxe * Processor Group Classes 773434Sesaxe * 783434Sesaxe * Processor group consumers may wish to maintain and associate specific 793434Sesaxe * data with the PGs they create. For this reason, a mechanism for creating 803434Sesaxe * class specific PGs exists. Classes may overload the default functions for 813434Sesaxe * creating, destroying, and associating CPUs with PGs, and may also register 823434Sesaxe * class specific callbacks to be invoked when the CPU related system 833434Sesaxe * configuration changes. Class specific data is stored/associated with 843434Sesaxe * PGs by incorporating the pg_t (or pghw_t, as appropriate), as the first 853434Sesaxe * element of a class specific PG object. In memory, such a structure may look 863434Sesaxe * like: 873434Sesaxe * 883434Sesaxe * ----------------------- - - - 893434Sesaxe * | common | | | | <--(pg_t *) 903434Sesaxe * ----------------------- | | - 913434Sesaxe * | HW specific | | | <-----(pghw_t *) 923434Sesaxe * ----------------------- | - 933434Sesaxe * | class specific | | <-------(pg_cmt_t *) 943434Sesaxe * ----------------------- - 953434Sesaxe * 963434Sesaxe * Access to the PG class specific data can be had by casting a pointer to 973434Sesaxe * it's class specific view. 983434Sesaxe */ 993434Sesaxe 1003434Sesaxe static pg_t *pg_alloc_default(pg_class_t); 1013434Sesaxe static void pg_free_default(pg_t *); 1023434Sesaxe 1033434Sesaxe /* 1043434Sesaxe * Bootstrap CPU specific PG data 1053434Sesaxe * See pg_cpu_bootstrap() 1063434Sesaxe */ 1073434Sesaxe static cpu_pg_t bootstrap_pg_data; 1083434Sesaxe 1093434Sesaxe /* 1103434Sesaxe * Bitset of allocated PG ids (they are sequential) 1113434Sesaxe * and the next free id in the set. 1123434Sesaxe */ 1133434Sesaxe static bitset_t pg_id_set; 1143434Sesaxe static pgid_t pg_id_next = 0; 1153434Sesaxe 1163434Sesaxe /* 1173434Sesaxe * Default and externed PG ops vectors 1183434Sesaxe */ 1193434Sesaxe static struct pg_ops pg_ops_default = { 1203434Sesaxe pg_alloc_default, /* alloc */ 1213434Sesaxe pg_free_default, /* free */ 1223434Sesaxe NULL, /* cpu_init */ 1233434Sesaxe NULL, /* cpu_fini */ 1243434Sesaxe NULL, /* cpu_active */ 1253434Sesaxe NULL, /* cpu_inactive */ 1263434Sesaxe NULL, /* cpupart_in */ 1273434Sesaxe NULL, /* cpupart_out */ 1283434Sesaxe NULL, /* cpupart_move */ 1293434Sesaxe NULL, /* cpu_belongs */ 1303434Sesaxe }; 1313434Sesaxe 1323434Sesaxe /* 1333434Sesaxe * Class specific PG allocation callbacks 1343434Sesaxe */ 1353434Sesaxe #define PG_ALLOC(class) \ 1363434Sesaxe (pg_classes[class].pgc_ops->alloc ? \ 1373434Sesaxe pg_classes[class].pgc_ops->alloc() : \ 1383434Sesaxe pg_classes[pg_default_cid].pgc_ops->alloc()) 1393434Sesaxe 1403434Sesaxe #define PG_FREE(pg) \ 1413434Sesaxe ((pg)->pg_class->pgc_ops->free ? \ 1423434Sesaxe (pg)->pg_class->pgc_ops->free(pg) : \ 1433434Sesaxe pg_classes[pg_default_cid].pgc_ops->free(pg)) \ 1443434Sesaxe 1453434Sesaxe 1463434Sesaxe /* 1473434Sesaxe * Class specific membership test callback 1483434Sesaxe */ 1493434Sesaxe #define PG_CPU_BELONGS(pg, cp) \ 1503434Sesaxe ((pg)->pg_class->pgc_ops->cpu_belongs ? \ 1513434Sesaxe (pg)->pg_class->pgc_ops->cpu_belongs(pg, cp) : 0) \ 1523434Sesaxe 1533434Sesaxe /* 1543434Sesaxe * CPU configuration callbacks 1553434Sesaxe */ 1563434Sesaxe #define PG_CPU_INIT(class, cp) \ 1573434Sesaxe { \ 1583434Sesaxe if (pg_classes[class].pgc_ops->cpu_init) \ 1593434Sesaxe pg_classes[class].pgc_ops->cpu_init(cp); \ 1603434Sesaxe } 1613434Sesaxe 1623434Sesaxe #define PG_CPU_FINI(class, cp) \ 1633434Sesaxe { \ 1643434Sesaxe if (pg_classes[class].pgc_ops->cpu_fini) \ 1653434Sesaxe pg_classes[class].pgc_ops->cpu_fini(cp); \ 1663434Sesaxe } 1673434Sesaxe 1683434Sesaxe #define PG_CPU_ACTIVE(class, cp) \ 1693434Sesaxe { \ 1703434Sesaxe if (pg_classes[class].pgc_ops->cpu_active) \ 1713434Sesaxe pg_classes[class].pgc_ops->cpu_active(cp); \ 1723434Sesaxe } 1733434Sesaxe 1743434Sesaxe #define PG_CPU_INACTIVE(class, cp) \ 1753434Sesaxe { \ 1763434Sesaxe if (pg_classes[class].pgc_ops->cpu_inactive) \ 1773434Sesaxe pg_classes[class].pgc_ops->cpu_inactive(cp); \ 1783434Sesaxe } 1793434Sesaxe 1803434Sesaxe /* 1813434Sesaxe * CPU / cpupart configuration callbacks 1823434Sesaxe */ 1833434Sesaxe #define PG_CPUPART_IN(class, cp, pp) \ 1843434Sesaxe { \ 1853434Sesaxe if (pg_classes[class].pgc_ops->cpupart_in) \ 1863434Sesaxe pg_classes[class].pgc_ops->cpupart_in(cp, pp); \ 1873434Sesaxe } 1883434Sesaxe 1893434Sesaxe #define PG_CPUPART_OUT(class, cp, pp) \ 1903434Sesaxe { \ 1913434Sesaxe if (pg_classes[class].pgc_ops->cpupart_out) \ 1923434Sesaxe pg_classes[class].pgc_ops->cpupart_out(cp, pp); \ 1933434Sesaxe } 1943434Sesaxe 1953434Sesaxe #define PG_CPUPART_MOVE(class, cp, old, new) \ 1963434Sesaxe { \ 1973434Sesaxe if (pg_classes[class].pgc_ops->cpupart_move) \ 1983434Sesaxe pg_classes[class].pgc_ops->cpupart_move(cp, old, new); \ 1993434Sesaxe } 2003434Sesaxe 2013434Sesaxe 2023434Sesaxe 2033434Sesaxe static pg_class_t *pg_classes; 2043434Sesaxe static int pg_nclasses; 2053434Sesaxe 2063434Sesaxe static pg_cid_t pg_default_cid; 2073434Sesaxe 2083434Sesaxe /* 2093434Sesaxe * Initialze common PG subsystem. Perform CPU 0 initialization 2103434Sesaxe */ 2113434Sesaxe void 2123434Sesaxe pg_init(void) 2133434Sesaxe { 2143434Sesaxe pg_default_cid = 2153434Sesaxe pg_class_register("default", &pg_ops_default, PGR_LOGICAL); 2163434Sesaxe } 2173434Sesaxe 2183434Sesaxe /* 2193434Sesaxe * Perform CPU 0 initialization 2203434Sesaxe */ 2213434Sesaxe void 2223434Sesaxe pg_cpu0_init(void) 2233434Sesaxe { 2243434Sesaxe extern void pghw_physid_create(); 2253434Sesaxe 2263434Sesaxe /* 2273434Sesaxe * Create the physical ID cache for the boot CPU 2283434Sesaxe */ 2293434Sesaxe pghw_physid_create(CPU); 2303434Sesaxe 2313434Sesaxe /* 2323434Sesaxe * pg_cpu_* require that cpu_lock be held 2333434Sesaxe */ 2343434Sesaxe mutex_enter(&cpu_lock); 2353434Sesaxe 2363434Sesaxe pg_cpu_init(CPU); 2373434Sesaxe pg_cpupart_in(CPU, &cp_default); 2383434Sesaxe pg_cpu_active(CPU); 2393434Sesaxe 2403434Sesaxe mutex_exit(&cpu_lock); 2413434Sesaxe } 2423434Sesaxe 2433434Sesaxe /* 244*3676Sesaxe * Invoked when topology for CPU0 changes 245*3676Sesaxe * post pg_cpu0_init(). 246*3676Sesaxe * 247*3676Sesaxe * Currently happens as a result of null_proc_lpa 248*3676Sesaxe * on Starcat. 249*3676Sesaxe */ 250*3676Sesaxe void 251*3676Sesaxe pg_cpu0_reinit(void) 252*3676Sesaxe { 253*3676Sesaxe mutex_enter(&cpu_lock); 254*3676Sesaxe pg_cpu_inactive(CPU); 255*3676Sesaxe pg_cpupart_out(CPU, &cp_default); 256*3676Sesaxe pg_cpu_fini(CPU); 257*3676Sesaxe 258*3676Sesaxe pg_cpu_init(CPU); 259*3676Sesaxe pg_cpupart_in(CPU, &cp_default); 260*3676Sesaxe pg_cpu_active(CPU); 261*3676Sesaxe mutex_exit(&cpu_lock); 262*3676Sesaxe } 263*3676Sesaxe 264*3676Sesaxe /* 2653434Sesaxe * Register a new PG class 2663434Sesaxe */ 2673434Sesaxe pg_cid_t 2683434Sesaxe pg_class_register(char *name, struct pg_ops *ops, pg_relation_t relation) 2693434Sesaxe { 2703434Sesaxe pg_class_t *newclass; 2713434Sesaxe pg_class_t *classes_old; 2723434Sesaxe id_t cid; 2733434Sesaxe 2743434Sesaxe mutex_enter(&cpu_lock); 2753434Sesaxe 2763434Sesaxe /* 2773434Sesaxe * Allocate a new pg_class_t in the pg_classes array 2783434Sesaxe */ 2793434Sesaxe if (pg_nclasses == 0) { 2803434Sesaxe pg_classes = kmem_zalloc(sizeof (pg_class_t), KM_SLEEP); 2813434Sesaxe } else { 2823434Sesaxe classes_old = pg_classes; 2833434Sesaxe pg_classes = 2843434Sesaxe kmem_zalloc(sizeof (pg_class_t) * (pg_nclasses + 1), 2853434Sesaxe KM_SLEEP); 2863434Sesaxe (void) kcopy(classes_old, pg_classes, 2873434Sesaxe sizeof (pg_class_t) * pg_nclasses); 2883434Sesaxe kmem_free(classes_old, sizeof (pg_class_t) * pg_nclasses); 2893434Sesaxe } 2903434Sesaxe 2913434Sesaxe cid = pg_nclasses++; 2923434Sesaxe newclass = &pg_classes[cid]; 2933434Sesaxe 2943434Sesaxe (void) strncpy(newclass->pgc_name, name, PG_CLASS_NAME_MAX); 2953434Sesaxe newclass->pgc_id = cid; 2963434Sesaxe newclass->pgc_ops = ops; 2973434Sesaxe newclass->pgc_relation = relation; 2983434Sesaxe 2993434Sesaxe mutex_exit(&cpu_lock); 3003434Sesaxe 3013434Sesaxe return (cid); 3023434Sesaxe } 3033434Sesaxe 3043434Sesaxe /* 3053434Sesaxe * Try to find an existing pg in set in which to place cp. 3063434Sesaxe * Returns the pg if found, and NULL otherwise. 3073434Sesaxe * In the event that the CPU could belong to multiple 3083434Sesaxe * PGs in the set, the first matching PG will be returned. 3093434Sesaxe */ 3103434Sesaxe pg_t * 3113434Sesaxe pg_cpu_find_pg(cpu_t *cp, group_t *set) 3123434Sesaxe { 3133434Sesaxe pg_t *pg; 3143434Sesaxe group_iter_t i; 3153434Sesaxe 3163434Sesaxe group_iter_init(&i); 3173434Sesaxe while ((pg = group_iterate(set, &i)) != NULL) { 3183434Sesaxe /* 3193434Sesaxe * Ask the class if the CPU belongs here 3203434Sesaxe */ 3213434Sesaxe if (PG_CPU_BELONGS(pg, cp)) 3223434Sesaxe return (pg); 3233434Sesaxe } 3243434Sesaxe return (NULL); 3253434Sesaxe } 3263434Sesaxe 3273434Sesaxe /* 3283434Sesaxe * Iterate over the CPUs in a PG after initializing 3293434Sesaxe * the iterator with PG_CPU_ITR_INIT() 3303434Sesaxe */ 3313434Sesaxe cpu_t * 3323434Sesaxe pg_cpu_next(pg_cpu_itr_t *itr) 3333434Sesaxe { 3343434Sesaxe cpu_t *cpu; 3353434Sesaxe pg_t *pg = itr->pg; 3363434Sesaxe 3373434Sesaxe cpu = group_iterate(&pg->pg_cpus, &itr->position); 3383434Sesaxe return (cpu); 3393434Sesaxe } 3403434Sesaxe 3413434Sesaxe /* 3423434Sesaxe * Create a PG of a given class. 3433434Sesaxe * This routine may block. 3443434Sesaxe */ 3453434Sesaxe pg_t * 3463434Sesaxe pg_create(pg_cid_t cid) 3473434Sesaxe { 3483434Sesaxe pg_t *pg; 3493434Sesaxe pgid_t id; 3503434Sesaxe 3513434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 3523434Sesaxe 3533434Sesaxe /* 3543434Sesaxe * Call the class specific PG allocation routine 3553434Sesaxe */ 3563434Sesaxe pg = PG_ALLOC(cid); 3573434Sesaxe pg->pg_class = &pg_classes[cid]; 3583434Sesaxe pg->pg_relation = pg->pg_class->pgc_relation; 3593434Sesaxe 3603434Sesaxe /* 3613434Sesaxe * Find the next free sequential pg id 3623434Sesaxe */ 3633434Sesaxe do { 3643434Sesaxe if (pg_id_next >= bitset_capacity(&pg_id_set)) 3653434Sesaxe bitset_resize(&pg_id_set, pg_id_next + 1); 3663434Sesaxe id = pg_id_next++; 3673434Sesaxe } while (bitset_in_set(&pg_id_set, id)); 3683434Sesaxe 3693434Sesaxe pg->pg_id = id; 3703434Sesaxe bitset_add(&pg_id_set, pg->pg_id); 3713434Sesaxe 3723434Sesaxe /* 3733434Sesaxe * Create the PG's CPU group 3743434Sesaxe */ 3753434Sesaxe group_create(&pg->pg_cpus); 3763434Sesaxe 3773434Sesaxe return (pg); 3783434Sesaxe } 3793434Sesaxe 3803434Sesaxe /* 3813434Sesaxe * Destroy a PG. 3823434Sesaxe * This routine may block. 3833434Sesaxe */ 3843434Sesaxe void 3853434Sesaxe pg_destroy(pg_t *pg) 3863434Sesaxe { 3873434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 3883434Sesaxe 3893434Sesaxe group_destroy(&pg->pg_cpus); 3903434Sesaxe 3913434Sesaxe /* 3923434Sesaxe * Unassign the pg_id 3933434Sesaxe */ 3943434Sesaxe if (pg_id_next > pg->pg_id) 3953434Sesaxe pg_id_next = pg->pg_id; 3963434Sesaxe bitset_del(&pg_id_set, pg->pg_id); 3973434Sesaxe 3983434Sesaxe /* 3993434Sesaxe * Invoke the class specific de-allocation routine 4003434Sesaxe */ 4013434Sesaxe PG_FREE(pg); 4023434Sesaxe } 4033434Sesaxe 4043434Sesaxe /* 4053434Sesaxe * Add the CPU "cp" to processor group "pg" 4063434Sesaxe * This routine may block. 4073434Sesaxe */ 4083434Sesaxe void 4093434Sesaxe pg_cpu_add(pg_t *pg, cpu_t *cp) 4103434Sesaxe { 4113434Sesaxe int err; 4123434Sesaxe 4133434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 4143434Sesaxe 4153434Sesaxe /* This adds the CPU to the PG's CPU group */ 4163434Sesaxe err = group_add(&pg->pg_cpus, cp, GRP_RESIZE); 4173434Sesaxe ASSERT(err == 0); 4183434Sesaxe 4193434Sesaxe /* This adds the PG to the CPUs PG group */ 4203434Sesaxe ASSERT(cp->cpu_pg != &bootstrap_pg_data); 4213434Sesaxe err = group_add(&cp->cpu_pg->pgs, pg, GRP_RESIZE); 4223434Sesaxe ASSERT(err == 0); 4233434Sesaxe } 4243434Sesaxe 4253434Sesaxe /* 4263434Sesaxe * Remove "cp" from "pg". 4273434Sesaxe * This routine may block. 4283434Sesaxe */ 4293434Sesaxe void 4303434Sesaxe pg_cpu_delete(pg_t *pg, cpu_t *cp) 4313434Sesaxe { 4323434Sesaxe int err; 4333434Sesaxe 4343434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 4353434Sesaxe 4363434Sesaxe /* Remove the CPU from the PG */ 4373434Sesaxe err = group_remove(&pg->pg_cpus, cp, GRP_RESIZE); 4383434Sesaxe ASSERT(err == 0); 4393434Sesaxe 4403434Sesaxe /* Remove the PG from the CPU's PG group */ 4413434Sesaxe ASSERT(cp->cpu_pg != &bootstrap_pg_data); 4423434Sesaxe err = group_remove(&cp->cpu_pg->pgs, pg, GRP_RESIZE); 4433434Sesaxe ASSERT(err == 0); 4443434Sesaxe } 4453434Sesaxe 4463434Sesaxe /* 4473434Sesaxe * Allocate a CPU's PG data. This hangs off struct cpu at cpu_pg 4483434Sesaxe */ 4493434Sesaxe static cpu_pg_t * 4503434Sesaxe pg_cpu_data_alloc(void) 4513434Sesaxe { 4523434Sesaxe cpu_pg_t *pgd; 4533434Sesaxe 4543434Sesaxe pgd = kmem_zalloc(sizeof (cpu_pg_t), KM_SLEEP); 4553434Sesaxe group_create(&pgd->pgs); 4563434Sesaxe group_create(&pgd->cmt_pgs); 4573434Sesaxe 4583434Sesaxe return (pgd); 4593434Sesaxe } 4603434Sesaxe 4613434Sesaxe /* 4623434Sesaxe * Free the CPU's PG data. 4633434Sesaxe */ 4643434Sesaxe static void 4653434Sesaxe pg_cpu_data_free(cpu_pg_t *pgd) 4663434Sesaxe { 4673434Sesaxe group_destroy(&pgd->pgs); 4683434Sesaxe group_destroy(&pgd->cmt_pgs); 4693434Sesaxe kmem_free(pgd, sizeof (cpu_pg_t)); 4703434Sesaxe } 4713434Sesaxe 4723434Sesaxe /* 4733434Sesaxe * A new CPU is coming into the system, either via booting or DR. 4743434Sesaxe * Allocate it's PG data, and notify all registered classes about 4753434Sesaxe * the new CPU. 4763434Sesaxe * 4773434Sesaxe * This routine may block. 4783434Sesaxe */ 4793434Sesaxe void 4803434Sesaxe pg_cpu_init(cpu_t *cp) 4813434Sesaxe { 4823434Sesaxe pg_cid_t i; 4833434Sesaxe 4843434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 4853434Sesaxe 4863434Sesaxe /* 4873434Sesaxe * Allocate and size the per CPU pg data 4883434Sesaxe */ 4893434Sesaxe cp->cpu_pg = pg_cpu_data_alloc(); 4903434Sesaxe 4913434Sesaxe /* 4923434Sesaxe * Notify all registered classes about the new CPU 4933434Sesaxe */ 4943434Sesaxe for (i = 0; i < pg_nclasses; i++) 4953434Sesaxe PG_CPU_INIT(i, cp); 4963434Sesaxe } 4973434Sesaxe 4983434Sesaxe /* 4993434Sesaxe * This CPU is being deleted from the system. Notify the classes 5003434Sesaxe * and free up the CPU's PG data. 5013434Sesaxe */ 5023434Sesaxe void 5033434Sesaxe pg_cpu_fini(cpu_t *cp) 5043434Sesaxe { 5053434Sesaxe pg_cid_t i; 5063434Sesaxe 5073434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 5083434Sesaxe 5093434Sesaxe /* 5103434Sesaxe * This can happen if the CPU coming into the system 5113434Sesaxe * failed to power on. 5123434Sesaxe */ 5133434Sesaxe if (cp->cpu_pg == NULL || 5143434Sesaxe cp->cpu_pg == &bootstrap_pg_data) 5153434Sesaxe return; 5163434Sesaxe 5173434Sesaxe for (i = 0; i < pg_nclasses; i++) 5183434Sesaxe PG_CPU_FINI(i, cp); 5193434Sesaxe 5203434Sesaxe pg_cpu_data_free(cp->cpu_pg); 5213434Sesaxe cp->cpu_pg = NULL; 5223434Sesaxe } 5233434Sesaxe 5243434Sesaxe /* 5253434Sesaxe * This CPU is becoming active (online) 5263434Sesaxe * This routine may not block as it is called from paused CPUs 5273434Sesaxe * context. 5283434Sesaxe */ 5293434Sesaxe void 5303434Sesaxe pg_cpu_active(cpu_t *cp) 5313434Sesaxe { 5323434Sesaxe pg_cid_t i; 5333434Sesaxe 5343434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 5353434Sesaxe 5363434Sesaxe /* 5373434Sesaxe * Notify all registered classes about the new CPU 5383434Sesaxe */ 5393434Sesaxe for (i = 0; i < pg_nclasses; i++) 5403434Sesaxe PG_CPU_ACTIVE(i, cp); 5413434Sesaxe } 5423434Sesaxe 5433434Sesaxe /* 5443434Sesaxe * This CPU is going inactive (offline) 5453434Sesaxe * This routine may not block, as it is called from paused 5463434Sesaxe * CPUs context. 5473434Sesaxe */ 5483434Sesaxe void 5493434Sesaxe pg_cpu_inactive(cpu_t *cp) 5503434Sesaxe { 5513434Sesaxe pg_cid_t i; 5523434Sesaxe 5533434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 5543434Sesaxe 5553434Sesaxe /* 5563434Sesaxe * Notify all registered classes about the new CPU 5573434Sesaxe */ 5583434Sesaxe for (i = 0; i < pg_nclasses; i++) 5593434Sesaxe PG_CPU_INACTIVE(i, cp); 5603434Sesaxe } 5613434Sesaxe 5623434Sesaxe /* 5633434Sesaxe * Invoked when the CPU is about to move into the partition 5643434Sesaxe * This routine may block. 5653434Sesaxe */ 5663434Sesaxe void 5673434Sesaxe pg_cpupart_in(cpu_t *cp, cpupart_t *pp) 5683434Sesaxe { 5693434Sesaxe int i; 5703434Sesaxe 5713434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 5723434Sesaxe 5733434Sesaxe /* 5743434Sesaxe * Notify all registered classes that the 5753434Sesaxe * CPU is about to enter the CPU partition 5763434Sesaxe */ 5773434Sesaxe for (i = 0; i < pg_nclasses; i++) 5783434Sesaxe PG_CPUPART_IN(i, cp, pp); 5793434Sesaxe } 5803434Sesaxe 5813434Sesaxe /* 5823434Sesaxe * Invoked when the CPU is about to move out of the partition 5833434Sesaxe * This routine may block. 5843434Sesaxe */ 5853434Sesaxe /*ARGSUSED*/ 5863434Sesaxe void 5873434Sesaxe pg_cpupart_out(cpu_t *cp, cpupart_t *pp) 5883434Sesaxe { 5893434Sesaxe int i; 5903434Sesaxe 5913434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 5923434Sesaxe 5933434Sesaxe /* 5943434Sesaxe * Notify all registered classes that the 5953434Sesaxe * CPU is about to leave the CPU partition 5963434Sesaxe */ 5973434Sesaxe for (i = 0; i < pg_nclasses; i++) 5983434Sesaxe PG_CPUPART_OUT(i, cp, pp); 5993434Sesaxe } 6003434Sesaxe 6013434Sesaxe /* 6023434Sesaxe * Invoked when the CPU is *moving* partitions. 6033434Sesaxe * 6043434Sesaxe * This routine may not block, as it is called from paused CPUs 6053434Sesaxe * context. 6063434Sesaxe */ 6073434Sesaxe void 6083434Sesaxe pg_cpupart_move(cpu_t *cp, cpupart_t *oldpp, cpupart_t *newpp) 6093434Sesaxe { 6103434Sesaxe int i; 6113434Sesaxe 6123434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 6133434Sesaxe 6143434Sesaxe /* 6153434Sesaxe * Notify all registered classes that the 6163434Sesaxe * CPU is about to leave the CPU partition 6173434Sesaxe */ 6183434Sesaxe for (i = 0; i < pg_nclasses; i++) 6193434Sesaxe PG_CPUPART_MOVE(i, cp, oldpp, newpp); 6203434Sesaxe } 6213434Sesaxe 6223434Sesaxe /* 6233434Sesaxe * Provide the specified CPU a bootstrap pg 6243434Sesaxe * This is needed to allow sane behaviour if any PG consuming 6253434Sesaxe * code needs to deal with a partially initialized CPU 6263434Sesaxe */ 6273434Sesaxe void 6283434Sesaxe pg_cpu_bootstrap(cpu_t *cp) 6293434Sesaxe { 6303434Sesaxe cp->cpu_pg = &bootstrap_pg_data; 6313434Sesaxe } 6323434Sesaxe 6333434Sesaxe /*ARGSUSED*/ 6343434Sesaxe static pg_t * 6353434Sesaxe pg_alloc_default(pg_class_t class) 6363434Sesaxe { 6373434Sesaxe return (kmem_zalloc(sizeof (pg_t), KM_SLEEP)); 6383434Sesaxe } 6393434Sesaxe 6403434Sesaxe /*ARGSUSED*/ 6413434Sesaxe static void 6423434Sesaxe pg_free_default(struct pg *pg) 6433434Sesaxe { 6443434Sesaxe kmem_free(pg, sizeof (pg_t)); 6453434Sesaxe } 646