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 /*
228906SEric.Saxe@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
233434Sesaxe * Use is subject to license terms.
243434Sesaxe */
253434Sesaxe
263434Sesaxe #include <sys/systm.h>
273434Sesaxe #include <sys/types.h>
283434Sesaxe #include <sys/param.h>
293434Sesaxe #include <sys/thread.h>
303434Sesaxe #include <sys/cpuvar.h>
313434Sesaxe #include <sys/cpupart.h>
323434Sesaxe #include <sys/kmem.h>
333434Sesaxe #include <sys/cmn_err.h>
343434Sesaxe #include <sys/kstat.h>
353434Sesaxe #include <sys/processor.h>
363434Sesaxe #include <sys/disp.h>
373434Sesaxe #include <sys/group.h>
383434Sesaxe #include <sys/pg.h>
393434Sesaxe
403434Sesaxe /*
413434Sesaxe * Processor groups
423434Sesaxe *
433434Sesaxe * With the introduction of Chip Multi-Threaded (CMT) processor architectures,
443434Sesaxe * it is no longer necessarily true that a given physical processor module
453434Sesaxe * will present itself as a single schedulable entity (cpu_t). Rather, each
463434Sesaxe * chip and/or processor core may present itself as one or more "logical" CPUs.
473434Sesaxe *
483434Sesaxe * The logical CPUs presented may share physical components such as caches,
493434Sesaxe * data pipes, execution pipelines, FPUs, etc. It is advantageous to have the
503434Sesaxe * kernel be aware of the relationships existing between logical CPUs so that
513434Sesaxe * the appropriate optmizations may be employed.
523434Sesaxe *
533434Sesaxe * The processor group abstraction represents a set of logical CPUs that
543434Sesaxe * generally share some sort of physical or characteristic relationship.
553434Sesaxe *
563434Sesaxe * In the case of a physical sharing relationship, the CPUs in the group may
573434Sesaxe * share a pipeline, cache or floating point unit. In the case of a logical
583434Sesaxe * relationship, a PG may represent the set of CPUs in a processor set, or the
593434Sesaxe * set of CPUs running at a particular clock speed.
603434Sesaxe *
613434Sesaxe * The generic processor group structure, pg_t, contains the elements generic
623434Sesaxe * to a group of CPUs. Depending on the nature of the CPU relationship
633434Sesaxe * (LOGICAL or PHYSICAL), a pointer to a pg may be recast to a "view" of that
643434Sesaxe * PG where more specific data is represented.
653434Sesaxe *
663434Sesaxe * As an example, a PG representing a PHYSICAL relationship, may be recast to
673434Sesaxe * a pghw_t, where data further describing the hardware sharing relationship
683434Sesaxe * is maintained. See pghw.c and pghw.h for details on physical PGs.
693434Sesaxe *
703434Sesaxe * At this time a more specialized casting of a PG representing a LOGICAL
713434Sesaxe * relationship has not been implemented, but the architecture allows for this
723434Sesaxe * in the future.
733434Sesaxe *
743434Sesaxe * Processor Group Classes
753434Sesaxe *
763434Sesaxe * Processor group consumers may wish to maintain and associate specific
773434Sesaxe * data with the PGs they create. For this reason, a mechanism for creating
783434Sesaxe * class specific PGs exists. Classes may overload the default functions for
793434Sesaxe * creating, destroying, and associating CPUs with PGs, and may also register
803434Sesaxe * class specific callbacks to be invoked when the CPU related system
813434Sesaxe * configuration changes. Class specific data is stored/associated with
823434Sesaxe * PGs by incorporating the pg_t (or pghw_t, as appropriate), as the first
833434Sesaxe * element of a class specific PG object. In memory, such a structure may look
843434Sesaxe * like:
853434Sesaxe *
863434Sesaxe * ----------------------- - - -
873434Sesaxe * | common | | | | <--(pg_t *)
883434Sesaxe * ----------------------- | | -
893434Sesaxe * | HW specific | | | <-----(pghw_t *)
903434Sesaxe * ----------------------- | -
913434Sesaxe * | class specific | | <-------(pg_cmt_t *)
923434Sesaxe * ----------------------- -
933434Sesaxe *
943434Sesaxe * Access to the PG class specific data can be had by casting a pointer to
953434Sesaxe * it's class specific view.
963434Sesaxe */
973434Sesaxe
983434Sesaxe static pg_t *pg_alloc_default(pg_class_t);
993434Sesaxe static void pg_free_default(pg_t *);
1008906SEric.Saxe@Sun.COM static void pg_null_op();
1013434Sesaxe
1023434Sesaxe /*
1033434Sesaxe * Bootstrap CPU specific PG data
1043434Sesaxe * See pg_cpu_bootstrap()
1053434Sesaxe */
1063434Sesaxe static cpu_pg_t bootstrap_pg_data;
1073434Sesaxe
1083434Sesaxe /*
1093434Sesaxe * Bitset of allocated PG ids (they are sequential)
1103434Sesaxe * and the next free id in the set.
1113434Sesaxe */
1123434Sesaxe static bitset_t pg_id_set;
113*11389SAlexander.Kolbasov@Sun.COM
114*11389SAlexander.Kolbasov@Sun.COM /*
115*11389SAlexander.Kolbasov@Sun.COM * ID space starts from 1 to assume that root has ID 0;
116*11389SAlexander.Kolbasov@Sun.COM */
117*11389SAlexander.Kolbasov@Sun.COM static pgid_t pg_id_next = 1;
1183434Sesaxe
1193434Sesaxe /*
1203434Sesaxe * Default and externed PG ops vectors
1213434Sesaxe */
1223434Sesaxe static struct pg_ops pg_ops_default = {
1233434Sesaxe pg_alloc_default, /* alloc */
1243434Sesaxe pg_free_default, /* free */
1253434Sesaxe NULL, /* cpu_init */
1263434Sesaxe NULL, /* cpu_fini */
1273434Sesaxe NULL, /* cpu_active */
1283434Sesaxe NULL, /* cpu_inactive */
1293434Sesaxe NULL, /* cpupart_in */
1303434Sesaxe NULL, /* cpupart_out */
1313434Sesaxe NULL, /* cpupart_move */
1323434Sesaxe NULL, /* cpu_belongs */
1338906SEric.Saxe@Sun.COM NULL, /* policy_name */
1348906SEric.Saxe@Sun.COM };
1358906SEric.Saxe@Sun.COM
1368906SEric.Saxe@Sun.COM static struct pg_cb_ops pg_cb_ops_default = {
1378906SEric.Saxe@Sun.COM pg_null_op, /* thread_swtch */
1388906SEric.Saxe@Sun.COM pg_null_op, /* thread_remain */
1393434Sesaxe };
1403434Sesaxe
1413434Sesaxe /*
1423434Sesaxe * Class specific PG allocation callbacks
1433434Sesaxe */
1443434Sesaxe #define PG_ALLOC(class) \
1453434Sesaxe (pg_classes[class].pgc_ops->alloc ? \
1463434Sesaxe pg_classes[class].pgc_ops->alloc() : \
1473434Sesaxe pg_classes[pg_default_cid].pgc_ops->alloc())
1483434Sesaxe
1493434Sesaxe #define PG_FREE(pg) \
1503434Sesaxe ((pg)->pg_class->pgc_ops->free ? \
1513434Sesaxe (pg)->pg_class->pgc_ops->free(pg) : \
1523434Sesaxe pg_classes[pg_default_cid].pgc_ops->free(pg)) \
1533434Sesaxe
1543434Sesaxe
1553434Sesaxe /*
1568906SEric.Saxe@Sun.COM * Class specific PG policy name
1578906SEric.Saxe@Sun.COM */
1588906SEric.Saxe@Sun.COM #define PG_POLICY_NAME(pg) \
1598906SEric.Saxe@Sun.COM ((pg)->pg_class->pgc_ops->policy_name ? \
1608906SEric.Saxe@Sun.COM (pg)->pg_class->pgc_ops->policy_name(pg) : NULL) \
1618906SEric.Saxe@Sun.COM
1628906SEric.Saxe@Sun.COM /*
1633434Sesaxe * Class specific membership test callback
1643434Sesaxe */
1653434Sesaxe #define PG_CPU_BELONGS(pg, cp) \
1663434Sesaxe ((pg)->pg_class->pgc_ops->cpu_belongs ? \
1673434Sesaxe (pg)->pg_class->pgc_ops->cpu_belongs(pg, cp) : 0) \
1683434Sesaxe
1693434Sesaxe /*
1703434Sesaxe * CPU configuration callbacks
1713434Sesaxe */
1729352SEric.Saxe@Sun.COM #define PG_CPU_INIT(class, cp, cpu_pg) \
1733434Sesaxe { \
1743434Sesaxe if (pg_classes[class].pgc_ops->cpu_init) \
1759352SEric.Saxe@Sun.COM pg_classes[class].pgc_ops->cpu_init(cp, cpu_pg); \
1763434Sesaxe }
1773434Sesaxe
1789352SEric.Saxe@Sun.COM #define PG_CPU_FINI(class, cp, cpu_pg) \
1793434Sesaxe { \
1803434Sesaxe if (pg_classes[class].pgc_ops->cpu_fini) \
1819352SEric.Saxe@Sun.COM pg_classes[class].pgc_ops->cpu_fini(cp, cpu_pg); \
1823434Sesaxe }
1833434Sesaxe
1843434Sesaxe #define PG_CPU_ACTIVE(class, cp) \
1853434Sesaxe { \
1863434Sesaxe if (pg_classes[class].pgc_ops->cpu_active) \
1873434Sesaxe pg_classes[class].pgc_ops->cpu_active(cp); \
1883434Sesaxe }
1893434Sesaxe
1903434Sesaxe #define PG_CPU_INACTIVE(class, cp) \
1913434Sesaxe { \
1923434Sesaxe if (pg_classes[class].pgc_ops->cpu_inactive) \
1933434Sesaxe pg_classes[class].pgc_ops->cpu_inactive(cp); \
1943434Sesaxe }
1953434Sesaxe
1963434Sesaxe /*
1973434Sesaxe * CPU / cpupart configuration callbacks
1983434Sesaxe */
1993434Sesaxe #define PG_CPUPART_IN(class, cp, pp) \
2003434Sesaxe { \
2013434Sesaxe if (pg_classes[class].pgc_ops->cpupart_in) \
2023434Sesaxe pg_classes[class].pgc_ops->cpupart_in(cp, pp); \
2033434Sesaxe }
2043434Sesaxe
2053434Sesaxe #define PG_CPUPART_OUT(class, cp, pp) \
2063434Sesaxe { \
2073434Sesaxe if (pg_classes[class].pgc_ops->cpupart_out) \
2083434Sesaxe pg_classes[class].pgc_ops->cpupart_out(cp, pp); \
2093434Sesaxe }
2103434Sesaxe
2113434Sesaxe #define PG_CPUPART_MOVE(class, cp, old, new) \
2123434Sesaxe { \
2133434Sesaxe if (pg_classes[class].pgc_ops->cpupart_move) \
2143434Sesaxe pg_classes[class].pgc_ops->cpupart_move(cp, old, new); \
2153434Sesaxe }
2163434Sesaxe
2173434Sesaxe
2183434Sesaxe
2193434Sesaxe static pg_class_t *pg_classes;
2203434Sesaxe static int pg_nclasses;
2213434Sesaxe
2223434Sesaxe static pg_cid_t pg_default_cid;
2233434Sesaxe
2243434Sesaxe /*
2258906SEric.Saxe@Sun.COM * Initialze common PG subsystem.
2263434Sesaxe */
2273434Sesaxe void
pg_init(void)2283434Sesaxe pg_init(void)
2293434Sesaxe {
2308906SEric.Saxe@Sun.COM extern void pg_cmt_class_init();
2319478SEric.Saxe@Sun.COM extern void pg_cmt_cpu_startup();
2328906SEric.Saxe@Sun.COM
2333434Sesaxe pg_default_cid =
2343434Sesaxe pg_class_register("default", &pg_ops_default, PGR_LOGICAL);
2358906SEric.Saxe@Sun.COM
2368906SEric.Saxe@Sun.COM /*
2378906SEric.Saxe@Sun.COM * Initialize classes to allow them to register with the framework
2388906SEric.Saxe@Sun.COM */
2398906SEric.Saxe@Sun.COM pg_cmt_class_init();
2408906SEric.Saxe@Sun.COM
2418906SEric.Saxe@Sun.COM pg_cpu0_init();
2429478SEric.Saxe@Sun.COM pg_cmt_cpu_startup(CPU);
2433434Sesaxe }
2443434Sesaxe
2453434Sesaxe /*
2463434Sesaxe * Perform CPU 0 initialization
2473434Sesaxe */
2483434Sesaxe void
pg_cpu0_init(void)2493434Sesaxe pg_cpu0_init(void)
2503434Sesaxe {
2513434Sesaxe extern void pghw_physid_create();
2523434Sesaxe
2533434Sesaxe /*
2543434Sesaxe * Create the physical ID cache for the boot CPU
2553434Sesaxe */
2563434Sesaxe pghw_physid_create(CPU);
2573434Sesaxe
2583434Sesaxe /*
2593434Sesaxe * pg_cpu_* require that cpu_lock be held
2603434Sesaxe */
2613434Sesaxe mutex_enter(&cpu_lock);
2623434Sesaxe
26311172SHaik.Aftandilian@Sun.COM (void) pg_cpu_init(CPU, B_FALSE);
2643434Sesaxe pg_cpupart_in(CPU, &cp_default);
2653434Sesaxe pg_cpu_active(CPU);
2663434Sesaxe
2673434Sesaxe mutex_exit(&cpu_lock);
2683434Sesaxe }
2693434Sesaxe
2703434Sesaxe /*
2713676Sesaxe * Invoked when topology for CPU0 changes
2723676Sesaxe * post pg_cpu0_init().
2733676Sesaxe *
2743676Sesaxe * Currently happens as a result of null_proc_lpa
2753676Sesaxe * on Starcat.
2763676Sesaxe */
2773676Sesaxe void
pg_cpu0_reinit(void)2783676Sesaxe pg_cpu0_reinit(void)
2793676Sesaxe {
2803676Sesaxe mutex_enter(&cpu_lock);
2813676Sesaxe pg_cpu_inactive(CPU);
2823676Sesaxe pg_cpupart_out(CPU, &cp_default);
28311172SHaik.Aftandilian@Sun.COM pg_cpu_fini(CPU, NULL);
2843676Sesaxe
28511172SHaik.Aftandilian@Sun.COM (void) pg_cpu_init(CPU, B_FALSE);
2863676Sesaxe pg_cpupart_in(CPU, &cp_default);
2873676Sesaxe pg_cpu_active(CPU);
2883676Sesaxe mutex_exit(&cpu_lock);
2893676Sesaxe }
2903676Sesaxe
2913676Sesaxe /*
2923434Sesaxe * Register a new PG class
2933434Sesaxe */
2943434Sesaxe pg_cid_t
pg_class_register(char * name,struct pg_ops * ops,pg_relation_t relation)2953434Sesaxe pg_class_register(char *name, struct pg_ops *ops, pg_relation_t relation)
2963434Sesaxe {
2973434Sesaxe pg_class_t *newclass;
2983434Sesaxe pg_class_t *classes_old;
2993434Sesaxe id_t cid;
3003434Sesaxe
3013434Sesaxe mutex_enter(&cpu_lock);
3023434Sesaxe
3033434Sesaxe /*
3043434Sesaxe * Allocate a new pg_class_t in the pg_classes array
3053434Sesaxe */
3063434Sesaxe if (pg_nclasses == 0) {
3073434Sesaxe pg_classes = kmem_zalloc(sizeof (pg_class_t), KM_SLEEP);
3083434Sesaxe } else {
3093434Sesaxe classes_old = pg_classes;
3103434Sesaxe pg_classes =
3113434Sesaxe kmem_zalloc(sizeof (pg_class_t) * (pg_nclasses + 1),
3128906SEric.Saxe@Sun.COM KM_SLEEP);
3133434Sesaxe (void) kcopy(classes_old, pg_classes,
3143434Sesaxe sizeof (pg_class_t) * pg_nclasses);
3153434Sesaxe kmem_free(classes_old, sizeof (pg_class_t) * pg_nclasses);
3163434Sesaxe }
3173434Sesaxe
3183434Sesaxe cid = pg_nclasses++;
3193434Sesaxe newclass = &pg_classes[cid];
3203434Sesaxe
3213434Sesaxe (void) strncpy(newclass->pgc_name, name, PG_CLASS_NAME_MAX);
3223434Sesaxe newclass->pgc_id = cid;
3233434Sesaxe newclass->pgc_ops = ops;
3243434Sesaxe newclass->pgc_relation = relation;
3253434Sesaxe
3263434Sesaxe mutex_exit(&cpu_lock);
3273434Sesaxe
3283434Sesaxe return (cid);
3293434Sesaxe }
3303434Sesaxe
3313434Sesaxe /*
3323434Sesaxe * Try to find an existing pg in set in which to place cp.
3333434Sesaxe * Returns the pg if found, and NULL otherwise.
3343434Sesaxe * In the event that the CPU could belong to multiple
3353434Sesaxe * PGs in the set, the first matching PG will be returned.
3363434Sesaxe */
3373434Sesaxe pg_t *
pg_cpu_find_pg(cpu_t * cp,group_t * set)3383434Sesaxe pg_cpu_find_pg(cpu_t *cp, group_t *set)
3393434Sesaxe {
3403434Sesaxe pg_t *pg;
3413434Sesaxe group_iter_t i;
3423434Sesaxe
3433434Sesaxe group_iter_init(&i);
3443434Sesaxe while ((pg = group_iterate(set, &i)) != NULL) {
3453434Sesaxe /*
3463434Sesaxe * Ask the class if the CPU belongs here
3473434Sesaxe */
3483434Sesaxe if (PG_CPU_BELONGS(pg, cp))
3493434Sesaxe return (pg);
3503434Sesaxe }
3513434Sesaxe return (NULL);
3523434Sesaxe }
3533434Sesaxe
3543434Sesaxe /*
3553434Sesaxe * Iterate over the CPUs in a PG after initializing
3563434Sesaxe * the iterator with PG_CPU_ITR_INIT()
3573434Sesaxe */
3583434Sesaxe cpu_t *
pg_cpu_next(pg_cpu_itr_t * itr)3593434Sesaxe pg_cpu_next(pg_cpu_itr_t *itr)
3603434Sesaxe {
3613434Sesaxe cpu_t *cpu;
3623434Sesaxe pg_t *pg = itr->pg;
3633434Sesaxe
3643434Sesaxe cpu = group_iterate(&pg->pg_cpus, &itr->position);
3653434Sesaxe return (cpu);
3663434Sesaxe }
3673434Sesaxe
3683434Sesaxe /*
3698906SEric.Saxe@Sun.COM * Test if a given PG contains a given CPU
3708906SEric.Saxe@Sun.COM */
3718906SEric.Saxe@Sun.COM boolean_t
pg_cpu_find(pg_t * pg,cpu_t * cp)3728906SEric.Saxe@Sun.COM pg_cpu_find(pg_t *pg, cpu_t *cp)
3738906SEric.Saxe@Sun.COM {
3748906SEric.Saxe@Sun.COM if (group_find(&pg->pg_cpus, cp) == (uint_t)-1)
3758906SEric.Saxe@Sun.COM return (B_FALSE);
3768906SEric.Saxe@Sun.COM
3778906SEric.Saxe@Sun.COM return (B_TRUE);
3788906SEric.Saxe@Sun.COM }
3798906SEric.Saxe@Sun.COM
3808906SEric.Saxe@Sun.COM /*
3818906SEric.Saxe@Sun.COM * Set the PGs callbacks to the default
3828906SEric.Saxe@Sun.COM */
3838906SEric.Saxe@Sun.COM void
pg_callback_set_defaults(pg_t * pg)3848906SEric.Saxe@Sun.COM pg_callback_set_defaults(pg_t *pg)
3858906SEric.Saxe@Sun.COM {
3868906SEric.Saxe@Sun.COM bcopy(&pg_cb_ops_default, &pg->pg_cb, sizeof (struct pg_cb_ops));
3878906SEric.Saxe@Sun.COM }
3888906SEric.Saxe@Sun.COM
3898906SEric.Saxe@Sun.COM /*
3903434Sesaxe * Create a PG of a given class.
3913434Sesaxe * This routine may block.
3923434Sesaxe */
3933434Sesaxe pg_t *
pg_create(pg_cid_t cid)3943434Sesaxe pg_create(pg_cid_t cid)
3953434Sesaxe {
3963434Sesaxe pg_t *pg;
3973434Sesaxe pgid_t id;
3983434Sesaxe
3993434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
4003434Sesaxe
4013434Sesaxe /*
4023434Sesaxe * Call the class specific PG allocation routine
4033434Sesaxe */
4043434Sesaxe pg = PG_ALLOC(cid);
4053434Sesaxe pg->pg_class = &pg_classes[cid];
4063434Sesaxe pg->pg_relation = pg->pg_class->pgc_relation;
4073434Sesaxe
4083434Sesaxe /*
4093434Sesaxe * Find the next free sequential pg id
4103434Sesaxe */
4113434Sesaxe do {
4123434Sesaxe if (pg_id_next >= bitset_capacity(&pg_id_set))
4133434Sesaxe bitset_resize(&pg_id_set, pg_id_next + 1);
4143434Sesaxe id = pg_id_next++;
4153434Sesaxe } while (bitset_in_set(&pg_id_set, id));
4163434Sesaxe
4173434Sesaxe pg->pg_id = id;
4183434Sesaxe bitset_add(&pg_id_set, pg->pg_id);
4193434Sesaxe
4203434Sesaxe /*
4213434Sesaxe * Create the PG's CPU group
4223434Sesaxe */
4233434Sesaxe group_create(&pg->pg_cpus);
4243434Sesaxe
4258906SEric.Saxe@Sun.COM /*
4268906SEric.Saxe@Sun.COM * Initialize the events ops vector
4278906SEric.Saxe@Sun.COM */
4288906SEric.Saxe@Sun.COM pg_callback_set_defaults(pg);
4298906SEric.Saxe@Sun.COM
4303434Sesaxe return (pg);
4313434Sesaxe }
4323434Sesaxe
4333434Sesaxe /*
4343434Sesaxe * Destroy a PG.
4353434Sesaxe * This routine may block.
4363434Sesaxe */
4373434Sesaxe void
pg_destroy(pg_t * pg)4383434Sesaxe pg_destroy(pg_t *pg)
4393434Sesaxe {
4403434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
4413434Sesaxe
4423434Sesaxe group_destroy(&pg->pg_cpus);
4433434Sesaxe
4443434Sesaxe /*
4453434Sesaxe * Unassign the pg_id
4463434Sesaxe */
4473434Sesaxe if (pg_id_next > pg->pg_id)
4483434Sesaxe pg_id_next = pg->pg_id;
4493434Sesaxe bitset_del(&pg_id_set, pg->pg_id);
4503434Sesaxe
4513434Sesaxe /*
4523434Sesaxe * Invoke the class specific de-allocation routine
4533434Sesaxe */
4543434Sesaxe PG_FREE(pg);
4553434Sesaxe }
4563434Sesaxe
4573434Sesaxe /*
4583434Sesaxe * Add the CPU "cp" to processor group "pg"
4593434Sesaxe * This routine may block.
4603434Sesaxe */
4613434Sesaxe void
pg_cpu_add(pg_t * pg,cpu_t * cp,cpu_pg_t * cpu_pg)4629352SEric.Saxe@Sun.COM pg_cpu_add(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg)
4633434Sesaxe {
4643434Sesaxe int err;
4653434Sesaxe
4663434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
4673434Sesaxe
4683434Sesaxe /* This adds the CPU to the PG's CPU group */
4693434Sesaxe err = group_add(&pg->pg_cpus, cp, GRP_RESIZE);
4703434Sesaxe ASSERT(err == 0);
4713434Sesaxe
4729352SEric.Saxe@Sun.COM /*
4739352SEric.Saxe@Sun.COM * The CPU should be referencing the bootstrap PG data still
4749352SEric.Saxe@Sun.COM * at this point, since this routine may block causing us to
4759352SEric.Saxe@Sun.COM * enter the dispatcher.
4769352SEric.Saxe@Sun.COM */
4779438SEric.Saxe@Sun.COM ASSERT(pg_cpu_is_bootstrapped(cp));
4789352SEric.Saxe@Sun.COM
4793434Sesaxe /* This adds the PG to the CPUs PG group */
4809352SEric.Saxe@Sun.COM err = group_add(&cpu_pg->pgs, pg, GRP_RESIZE);
4813434Sesaxe ASSERT(err == 0);
4823434Sesaxe }
4833434Sesaxe
4843434Sesaxe /*
4853434Sesaxe * Remove "cp" from "pg".
4863434Sesaxe * This routine may block.
4873434Sesaxe */
4883434Sesaxe void
pg_cpu_delete(pg_t * pg,cpu_t * cp,cpu_pg_t * cpu_pg)4899352SEric.Saxe@Sun.COM pg_cpu_delete(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg)
4903434Sesaxe {
4913434Sesaxe int err;
4923434Sesaxe
4933434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
4943434Sesaxe
4953434Sesaxe /* Remove the CPU from the PG */
4963434Sesaxe err = group_remove(&pg->pg_cpus, cp, GRP_RESIZE);
4973434Sesaxe ASSERT(err == 0);
4983434Sesaxe
4999352SEric.Saxe@Sun.COM /*
5009352SEric.Saxe@Sun.COM * The CPU should be referencing the bootstrap PG data still
5019352SEric.Saxe@Sun.COM * at this point, since this routine may block causing us to
5029352SEric.Saxe@Sun.COM * enter the dispatcher.
5039352SEric.Saxe@Sun.COM */
5049438SEric.Saxe@Sun.COM ASSERT(pg_cpu_is_bootstrapped(cp));
5059352SEric.Saxe@Sun.COM
5063434Sesaxe /* Remove the PG from the CPU's PG group */
5079352SEric.Saxe@Sun.COM err = group_remove(&cpu_pg->pgs, pg, GRP_RESIZE);
5083434Sesaxe ASSERT(err == 0);
5093434Sesaxe }
5103434Sesaxe
5113434Sesaxe /*
5123434Sesaxe * Allocate a CPU's PG data. This hangs off struct cpu at cpu_pg
5133434Sesaxe */
5143434Sesaxe static cpu_pg_t *
pg_cpu_data_alloc(void)5153434Sesaxe pg_cpu_data_alloc(void)
5163434Sesaxe {
5173434Sesaxe cpu_pg_t *pgd;
5183434Sesaxe
5193434Sesaxe pgd = kmem_zalloc(sizeof (cpu_pg_t), KM_SLEEP);
5203434Sesaxe group_create(&pgd->pgs);
5213434Sesaxe group_create(&pgd->cmt_pgs);
5223434Sesaxe
5233434Sesaxe return (pgd);
5243434Sesaxe }
5253434Sesaxe
5263434Sesaxe /*
5273434Sesaxe * Free the CPU's PG data.
5283434Sesaxe */
5293434Sesaxe static void
pg_cpu_data_free(cpu_pg_t * pgd)5303434Sesaxe pg_cpu_data_free(cpu_pg_t *pgd)
5313434Sesaxe {
5323434Sesaxe group_destroy(&pgd->pgs);
5333434Sesaxe group_destroy(&pgd->cmt_pgs);
5343434Sesaxe kmem_free(pgd, sizeof (cpu_pg_t));
5353434Sesaxe }
5363434Sesaxe
5373434Sesaxe /*
53811172SHaik.Aftandilian@Sun.COM * Called when either a new CPU is coming into the system (either
53911172SHaik.Aftandilian@Sun.COM * via booting or DR) or when the CPU's PG data is being recalculated.
54011172SHaik.Aftandilian@Sun.COM * Allocate its PG data, and notify all registered classes about
5413434Sesaxe * the new CPU.
5423434Sesaxe *
54311172SHaik.Aftandilian@Sun.COM * If "deferred_init" is B_TRUE, the CPU's PG data will be allocated
54411172SHaik.Aftandilian@Sun.COM * and returned, but the "bootstrap" structure will be left in place.
54511172SHaik.Aftandilian@Sun.COM * The deferred_init option is used when all CPUs in the system are
54611172SHaik.Aftandilian@Sun.COM * using the bootstrap structure as part of the process of recalculating
54711172SHaik.Aftandilian@Sun.COM * all PG data. The caller must replace the bootstrap structure with the
54811172SHaik.Aftandilian@Sun.COM * allocated PG data before pg_cpu_active is called.
54911172SHaik.Aftandilian@Sun.COM *
5503434Sesaxe * This routine may block.
5513434Sesaxe */
55211172SHaik.Aftandilian@Sun.COM cpu_pg_t *
pg_cpu_init(cpu_t * cp,boolean_t deferred_init)55311172SHaik.Aftandilian@Sun.COM pg_cpu_init(cpu_t *cp, boolean_t deferred_init)
5543434Sesaxe {
5553434Sesaxe pg_cid_t i;
5569352SEric.Saxe@Sun.COM cpu_pg_t *cpu_pg;
5573434Sesaxe
5583434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
5593434Sesaxe
5603434Sesaxe /*
5613434Sesaxe * Allocate and size the per CPU pg data
5629352SEric.Saxe@Sun.COM *
5639352SEric.Saxe@Sun.COM * The CPU's PG data will be populated by the various
5649352SEric.Saxe@Sun.COM * PG classes during the invocation of the PG_CPU_INIT()
5659352SEric.Saxe@Sun.COM * callback below.
5669352SEric.Saxe@Sun.COM *
5679352SEric.Saxe@Sun.COM * Since the we could block and enter the dispatcher during
5689352SEric.Saxe@Sun.COM * this process, the CPU will continue to reference the bootstrap
5699352SEric.Saxe@Sun.COM * PG data until all the initialization completes.
5703434Sesaxe */
5719438SEric.Saxe@Sun.COM ASSERT(pg_cpu_is_bootstrapped(cp));
5729352SEric.Saxe@Sun.COM
5739352SEric.Saxe@Sun.COM cpu_pg = pg_cpu_data_alloc();
5743434Sesaxe
5753434Sesaxe /*
5763434Sesaxe * Notify all registered classes about the new CPU
5773434Sesaxe */
5783434Sesaxe for (i = 0; i < pg_nclasses; i++)
5799352SEric.Saxe@Sun.COM PG_CPU_INIT(i, cp, cpu_pg);
5809352SEric.Saxe@Sun.COM
5819352SEric.Saxe@Sun.COM /*
5829352SEric.Saxe@Sun.COM * The CPU's PG data is now ready to use.
5839352SEric.Saxe@Sun.COM */
58411172SHaik.Aftandilian@Sun.COM if (deferred_init == B_FALSE)
58511172SHaik.Aftandilian@Sun.COM cp->cpu_pg = cpu_pg;
58611172SHaik.Aftandilian@Sun.COM
58711172SHaik.Aftandilian@Sun.COM return (cpu_pg);
5883434Sesaxe }
5893434Sesaxe
5903434Sesaxe /*
59111172SHaik.Aftandilian@Sun.COM * Either this CPU is being deleted from the system or its PG data is
59211172SHaik.Aftandilian@Sun.COM * being recalculated. Notify the classes and free up the CPU's PG data.
59311172SHaik.Aftandilian@Sun.COM *
59411172SHaik.Aftandilian@Sun.COM * If "cpu_pg_deferred" is non-NULL, it points to the CPU's PG data and
59511172SHaik.Aftandilian@Sun.COM * serves to indicate that this CPU is already using the bootstrap
59611172SHaik.Aftandilian@Sun.COM * stucture. Used as part of the process to recalculate the PG data for
59711172SHaik.Aftandilian@Sun.COM * all CPUs in the system.
5983434Sesaxe */
5993434Sesaxe void
pg_cpu_fini(cpu_t * cp,cpu_pg_t * cpu_pg_deferred)60011172SHaik.Aftandilian@Sun.COM pg_cpu_fini(cpu_t *cp, cpu_pg_t *cpu_pg_deferred)
6013434Sesaxe {
6023434Sesaxe pg_cid_t i;
6039352SEric.Saxe@Sun.COM cpu_pg_t *cpu_pg;
6043434Sesaxe
6053434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
6063434Sesaxe
60711172SHaik.Aftandilian@Sun.COM if (cpu_pg_deferred == NULL) {
60811172SHaik.Aftandilian@Sun.COM cpu_pg = cp->cpu_pg;
60911172SHaik.Aftandilian@Sun.COM
61011172SHaik.Aftandilian@Sun.COM /*
61111172SHaik.Aftandilian@Sun.COM * This can happen if the CPU coming into the system
61211172SHaik.Aftandilian@Sun.COM * failed to power on.
61311172SHaik.Aftandilian@Sun.COM */
61411172SHaik.Aftandilian@Sun.COM if (cpu_pg == NULL || pg_cpu_is_bootstrapped(cp))
61511172SHaik.Aftandilian@Sun.COM return;
6169352SEric.Saxe@Sun.COM
61711172SHaik.Aftandilian@Sun.COM /*
61811172SHaik.Aftandilian@Sun.COM * Have the CPU reference the bootstrap PG data to survive
61911172SHaik.Aftandilian@Sun.COM * the dispatcher should it block from here on out.
62011172SHaik.Aftandilian@Sun.COM */
62111172SHaik.Aftandilian@Sun.COM pg_cpu_bootstrap(cp);
62211172SHaik.Aftandilian@Sun.COM } else {
62311172SHaik.Aftandilian@Sun.COM ASSERT(pg_cpu_is_bootstrapped(cp));
62411172SHaik.Aftandilian@Sun.COM cpu_pg = cpu_pg_deferred;
62511172SHaik.Aftandilian@Sun.COM }
6269352SEric.Saxe@Sun.COM
6273434Sesaxe for (i = 0; i < pg_nclasses; i++)
6289352SEric.Saxe@Sun.COM PG_CPU_FINI(i, cp, cpu_pg);
6293434Sesaxe
6309352SEric.Saxe@Sun.COM pg_cpu_data_free(cpu_pg);
6313434Sesaxe }
6323434Sesaxe
6333434Sesaxe /*
6343434Sesaxe * This CPU is becoming active (online)
6353434Sesaxe * This routine may not block as it is called from paused CPUs
6363434Sesaxe * context.
6373434Sesaxe */
6383434Sesaxe void
pg_cpu_active(cpu_t * cp)6393434Sesaxe pg_cpu_active(cpu_t *cp)
6403434Sesaxe {
6413434Sesaxe pg_cid_t i;
6423434Sesaxe
6433434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
6443434Sesaxe
6453434Sesaxe /*
6463434Sesaxe * Notify all registered classes about the new CPU
6473434Sesaxe */
6483434Sesaxe for (i = 0; i < pg_nclasses; i++)
6493434Sesaxe PG_CPU_ACTIVE(i, cp);
6503434Sesaxe }
6513434Sesaxe
6523434Sesaxe /*
6533434Sesaxe * This CPU is going inactive (offline)
6543434Sesaxe * This routine may not block, as it is called from paused
6553434Sesaxe * CPUs context.
6563434Sesaxe */
6573434Sesaxe void
pg_cpu_inactive(cpu_t * cp)6583434Sesaxe pg_cpu_inactive(cpu_t *cp)
6593434Sesaxe {
6603434Sesaxe pg_cid_t i;
6613434Sesaxe
6623434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
6633434Sesaxe
6643434Sesaxe /*
6653434Sesaxe * Notify all registered classes about the new CPU
6663434Sesaxe */
6673434Sesaxe for (i = 0; i < pg_nclasses; i++)
6683434Sesaxe PG_CPU_INACTIVE(i, cp);
6693434Sesaxe }
6703434Sesaxe
6713434Sesaxe /*
6723434Sesaxe * Invoked when the CPU is about to move into the partition
6733434Sesaxe * This routine may block.
6743434Sesaxe */
6753434Sesaxe void
pg_cpupart_in(cpu_t * cp,cpupart_t * pp)6763434Sesaxe pg_cpupart_in(cpu_t *cp, cpupart_t *pp)
6773434Sesaxe {
6783434Sesaxe int i;
6793434Sesaxe
6803434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
6813434Sesaxe
6823434Sesaxe /*
6833434Sesaxe * Notify all registered classes that the
6843434Sesaxe * CPU is about to enter the CPU partition
6853434Sesaxe */
6863434Sesaxe for (i = 0; i < pg_nclasses; i++)
6873434Sesaxe PG_CPUPART_IN(i, cp, pp);
6883434Sesaxe }
6893434Sesaxe
6903434Sesaxe /*
6913434Sesaxe * Invoked when the CPU is about to move out of the partition
6923434Sesaxe * This routine may block.
6933434Sesaxe */
6943434Sesaxe /*ARGSUSED*/
6953434Sesaxe void
pg_cpupart_out(cpu_t * cp,cpupart_t * pp)6963434Sesaxe pg_cpupart_out(cpu_t *cp, cpupart_t *pp)
6973434Sesaxe {
6983434Sesaxe int i;
6993434Sesaxe
7003434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
7013434Sesaxe
7023434Sesaxe /*
7033434Sesaxe * Notify all registered classes that the
7043434Sesaxe * CPU is about to leave the CPU partition
7053434Sesaxe */
7063434Sesaxe for (i = 0; i < pg_nclasses; i++)
7073434Sesaxe PG_CPUPART_OUT(i, cp, pp);
7083434Sesaxe }
7093434Sesaxe
7103434Sesaxe /*
7113434Sesaxe * Invoked when the CPU is *moving* partitions.
7123434Sesaxe *
7133434Sesaxe * This routine may not block, as it is called from paused CPUs
7143434Sesaxe * context.
7153434Sesaxe */
7163434Sesaxe void
pg_cpupart_move(cpu_t * cp,cpupart_t * oldpp,cpupart_t * newpp)7173434Sesaxe pg_cpupart_move(cpu_t *cp, cpupart_t *oldpp, cpupart_t *newpp)
7183434Sesaxe {
7193434Sesaxe int i;
7203434Sesaxe
7213434Sesaxe ASSERT(MUTEX_HELD(&cpu_lock));
7223434Sesaxe
7233434Sesaxe /*
7243434Sesaxe * Notify all registered classes that the
7253434Sesaxe * CPU is about to leave the CPU partition
7263434Sesaxe */
7273434Sesaxe for (i = 0; i < pg_nclasses; i++)
7283434Sesaxe PG_CPUPART_MOVE(i, cp, oldpp, newpp);
7293434Sesaxe }
7303434Sesaxe
7313434Sesaxe /*
7328906SEric.Saxe@Sun.COM * Return a class specific string describing a policy implemented
7338906SEric.Saxe@Sun.COM * across this PG
7348906SEric.Saxe@Sun.COM */
7358906SEric.Saxe@Sun.COM char *
pg_policy_name(pg_t * pg)7368906SEric.Saxe@Sun.COM pg_policy_name(pg_t *pg)
7378906SEric.Saxe@Sun.COM {
7388906SEric.Saxe@Sun.COM char *str;
7398906SEric.Saxe@Sun.COM if ((str = PG_POLICY_NAME(pg)) != NULL)
7408906SEric.Saxe@Sun.COM return (str);
7418906SEric.Saxe@Sun.COM
7428906SEric.Saxe@Sun.COM return ("N/A");
7438906SEric.Saxe@Sun.COM }
7448906SEric.Saxe@Sun.COM
7458906SEric.Saxe@Sun.COM /*
7463434Sesaxe * Provide the specified CPU a bootstrap pg
7473434Sesaxe * This is needed to allow sane behaviour if any PG consuming
7483434Sesaxe * code needs to deal with a partially initialized CPU
7493434Sesaxe */
7503434Sesaxe void
pg_cpu_bootstrap(cpu_t * cp)7513434Sesaxe pg_cpu_bootstrap(cpu_t *cp)
7523434Sesaxe {
7533434Sesaxe cp->cpu_pg = &bootstrap_pg_data;
7543434Sesaxe }
7553434Sesaxe
7569438SEric.Saxe@Sun.COM /*
7579438SEric.Saxe@Sun.COM * Return non-zero if the specified CPU is bootstrapped,
7589438SEric.Saxe@Sun.COM * which means it's CPU specific PG data has not yet been
7599438SEric.Saxe@Sun.COM * fully constructed.
7609438SEric.Saxe@Sun.COM */
7619438SEric.Saxe@Sun.COM int
pg_cpu_is_bootstrapped(cpu_t * cp)7629438SEric.Saxe@Sun.COM pg_cpu_is_bootstrapped(cpu_t *cp)
7639438SEric.Saxe@Sun.COM {
7649438SEric.Saxe@Sun.COM return (cp->cpu_pg == &bootstrap_pg_data);
7659438SEric.Saxe@Sun.COM }
7669438SEric.Saxe@Sun.COM
7673434Sesaxe /*ARGSUSED*/
7683434Sesaxe static pg_t *
pg_alloc_default(pg_class_t class)7693434Sesaxe pg_alloc_default(pg_class_t class)
7703434Sesaxe {
7713434Sesaxe return (kmem_zalloc(sizeof (pg_t), KM_SLEEP));
7723434Sesaxe }
7733434Sesaxe
7743434Sesaxe /*ARGSUSED*/
7753434Sesaxe static void
pg_free_default(struct pg * pg)7763434Sesaxe pg_free_default(struct pg *pg)
7773434Sesaxe {
7783434Sesaxe kmem_free(pg, sizeof (pg_t));
7793434Sesaxe }
7808906SEric.Saxe@Sun.COM
7818906SEric.Saxe@Sun.COM static void
pg_null_op()7828906SEric.Saxe@Sun.COM pg_null_op()
7838906SEric.Saxe@Sun.COM {
7848906SEric.Saxe@Sun.COM }
7858906SEric.Saxe@Sun.COM
7868906SEric.Saxe@Sun.COM /*
7878906SEric.Saxe@Sun.COM * Invoke the "thread switch" callback for each of the CPU's PGs
7888906SEric.Saxe@Sun.COM * This is invoked from the dispatcher swtch() routine, which is called
7898906SEric.Saxe@Sun.COM * when a thread running an a CPU should switch to another thread.
7908906SEric.Saxe@Sun.COM * "cp" is the CPU on which the thread switch is happening
7918906SEric.Saxe@Sun.COM * "now" is an unscaled hrtime_t timestamp taken in swtch()
7928906SEric.Saxe@Sun.COM * "old" and "new" are the outgoing and incoming threads, respectively.
7938906SEric.Saxe@Sun.COM */
7948906SEric.Saxe@Sun.COM void
pg_ev_thread_swtch(struct cpu * cp,hrtime_t now,kthread_t * old,kthread_t * new)7958906SEric.Saxe@Sun.COM pg_ev_thread_swtch(struct cpu *cp, hrtime_t now, kthread_t *old, kthread_t *new)
7968906SEric.Saxe@Sun.COM {
7978906SEric.Saxe@Sun.COM int i, sz;
7988906SEric.Saxe@Sun.COM group_t *grp;
7998906SEric.Saxe@Sun.COM pg_t *pg;
8008906SEric.Saxe@Sun.COM
8018906SEric.Saxe@Sun.COM grp = &cp->cpu_pg->pgs;
8028906SEric.Saxe@Sun.COM sz = GROUP_SIZE(grp);
8038906SEric.Saxe@Sun.COM for (i = 0; i < sz; i++) {
8048906SEric.Saxe@Sun.COM pg = GROUP_ACCESS(grp, i);
8058906SEric.Saxe@Sun.COM pg->pg_cb.thread_swtch(pg, cp, now, old, new);
8068906SEric.Saxe@Sun.COM }
8078906SEric.Saxe@Sun.COM }
8088906SEric.Saxe@Sun.COM
8098906SEric.Saxe@Sun.COM /*
8108906SEric.Saxe@Sun.COM * Invoke the "thread remain" callback for each of the CPU's PGs.
8118906SEric.Saxe@Sun.COM * This is called from the dispatcher's swtch() routine when a thread
8128906SEric.Saxe@Sun.COM * running on the CPU "cp" is switching to itself, which can happen as an
8138906SEric.Saxe@Sun.COM * artifact of the thread's timeslice expiring.
8148906SEric.Saxe@Sun.COM */
8158906SEric.Saxe@Sun.COM void
pg_ev_thread_remain(struct cpu * cp,kthread_t * t)8168906SEric.Saxe@Sun.COM pg_ev_thread_remain(struct cpu *cp, kthread_t *t)
8178906SEric.Saxe@Sun.COM {
8188906SEric.Saxe@Sun.COM int i, sz;
8198906SEric.Saxe@Sun.COM group_t *grp;
8208906SEric.Saxe@Sun.COM pg_t *pg;
8218906SEric.Saxe@Sun.COM
8228906SEric.Saxe@Sun.COM grp = &cp->cpu_pg->pgs;
8238906SEric.Saxe@Sun.COM sz = GROUP_SIZE(grp);
8248906SEric.Saxe@Sun.COM for (i = 0; i < sz; i++) {
8258906SEric.Saxe@Sun.COM pg = GROUP_ACCESS(grp, i);
8268906SEric.Saxe@Sun.COM pg->pg_cb.thread_remain(pg, cp, t);
8278906SEric.Saxe@Sun.COM }
8288906SEric.Saxe@Sun.COM }
829