xref: /titanic_50/usr/src/uts/common/os/pg.c (revision fb2f18f820d90b001aea4fb27dd654bc1263c440)
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