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