xref: /onnv-gate/usr/src/uts/common/os/pg.c (revision 3676:4975133d76f2)
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