xref: /titanic_54/usr/src/uts/common/os/pghw.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/kmem.h>
34*fb2f18f8Sesaxe #include <sys/cmn_err.h>
35*fb2f18f8Sesaxe #include <sys/group.h>
36*fb2f18f8Sesaxe #include <sys/pg.h>
37*fb2f18f8Sesaxe #include <sys/pghw.h>
38*fb2f18f8Sesaxe 
39*fb2f18f8Sesaxe /*
40*fb2f18f8Sesaxe  * Processor Groups: Hardware sharing relationship layer
41*fb2f18f8Sesaxe  *
42*fb2f18f8Sesaxe  * This file implements an extension to Processor Groups to capture
43*fb2f18f8Sesaxe  * hardware sharing relationships existing between logical CPUs. Examples of
44*fb2f18f8Sesaxe  * hardware sharing relationships include shared caches on some CMT
45*fb2f18f8Sesaxe  * procesoor architectures, or shared local memory controllers on NUMA
46*fb2f18f8Sesaxe  * based system architectures.
47*fb2f18f8Sesaxe  *
48*fb2f18f8Sesaxe  * The pghw_t structure represents the extended PG. The first member
49*fb2f18f8Sesaxe  * of the structure is the generic pg_t with the pghw specific members
50*fb2f18f8Sesaxe  * following. The generic pg_t *must* remain the first member of the
51*fb2f18f8Sesaxe  * structure as the code uses casting of structure references to access
52*fb2f18f8Sesaxe  * the generic pg_t structure elements.
53*fb2f18f8Sesaxe  *
54*fb2f18f8Sesaxe  * In addition to the generic CPU grouping, physical PGs have a hardware
55*fb2f18f8Sesaxe  * sharing relationship enumerated "type", and an instance id. The enumerated
56*fb2f18f8Sesaxe  * type is defined by the pghw_type_t enumeration, while the instance id
57*fb2f18f8Sesaxe  * uniquely identifies the sharing instance from among others of the same
58*fb2f18f8Sesaxe  * hardware sharing type.
59*fb2f18f8Sesaxe  *
60*fb2f18f8Sesaxe  * The physical PGs are organized into an overall hierarchy, and are tracked
61*fb2f18f8Sesaxe  * in a number of different per CPU, and per pghw_type_t type groups.
62*fb2f18f8Sesaxe  * As an example:
63*fb2f18f8Sesaxe  *
64*fb2f18f8Sesaxe  * -------------
65*fb2f18f8Sesaxe  * | pg_hw     |
66*fb2f18f8Sesaxe  * | (group_t) |
67*fb2f18f8Sesaxe  * -------------
68*fb2f18f8Sesaxe  *  ||                          ============================
69*fb2f18f8Sesaxe  *  ||\\-----------------------//       \\                 \\
70*fb2f18f8Sesaxe  *  ||  | hwset (PGC_HW_CHIP) |        -------------      -------------
71*fb2f18f8Sesaxe  *  ||  | (group_t)           |        | pghw_t    |      | pghw_t    |
72*fb2f18f8Sesaxe  *  ||  -----------------------        | chip 0    |      | chip 1    |
73*fb2f18f8Sesaxe  *  ||                                 -------------      -------------
74*fb2f18f8Sesaxe  *  ||                                 \\  \\  \\  \\     \\  \\  \\  \\
75*fb2f18f8Sesaxe  *  ||                                  cpu cpu cpu cpu    cpu cpu cpu cpu
76*fb2f18f8Sesaxe  *  ||
77*fb2f18f8Sesaxe  *  ||                          ============================
78*fb2f18f8Sesaxe  *  ||\\-----------------------//       \\                 \\
79*fb2f18f8Sesaxe  *  ||  | hwset (PGC_HW_IPIPE)|        -------------      -------------
80*fb2f18f8Sesaxe  *  ||  | (group_t)           |        | pghw_t    |      | pghw_t    |
81*fb2f18f8Sesaxe  *  ||  -----------------------        | ipipe 0   |      | ipipe 1   |
82*fb2f18f8Sesaxe  *  ||                                 -------------      -------------
83*fb2f18f8Sesaxe  *  ||                                 \\  \\             \\  \\
84*fb2f18f8Sesaxe  *  ||                                  cpu cpu            cpu cpu
85*fb2f18f8Sesaxe  *  ...
86*fb2f18f8Sesaxe  *
87*fb2f18f8Sesaxe  *
88*fb2f18f8Sesaxe  * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group
89*fb2f18f8Sesaxe  * of physical PGs of the same hardware sharing type. Within each hwset, the
90*fb2f18f8Sesaxe  * PG's instance id uniquely identifies the grouping relationshsip among other
91*fb2f18f8Sesaxe  * groupings of the same sharing type. The instance id for a grouping is
92*fb2f18f8Sesaxe  * platform defined, and in some cases may be used by platform code as a handle
93*fb2f18f8Sesaxe  * to search for a particular relationship instance.
94*fb2f18f8Sesaxe  *
95*fb2f18f8Sesaxe  * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs
96*fb2f18f8Sesaxe  * that participate in the sharing relationship. Each CPU also has associated
97*fb2f18f8Sesaxe  * with it a grouping tracking the PGs in which the CPU belongs. This can be
98*fb2f18f8Sesaxe  * used to iterate over the various relationships in which the CPU participates
99*fb2f18f8Sesaxe  * (the CPU's chip, cache, lgroup, etc.).
100*fb2f18f8Sesaxe  *
101*fb2f18f8Sesaxe  * The hwsets are created dynamically as new hardware sharing relationship types
102*fb2f18f8Sesaxe  * are instantiated. They are never destroyed, as once a given relathionship
103*fb2f18f8Sesaxe  * type appears in the system, it is quite likely that at least one instance of
104*fb2f18f8Sesaxe  * that relationship will always persist as long as the system is running.
105*fb2f18f8Sesaxe  */
106*fb2f18f8Sesaxe 
107*fb2f18f8Sesaxe static group_t		*pg_hw;		/* top level pg hw group */
108*fb2f18f8Sesaxe 
109*fb2f18f8Sesaxe /*
110*fb2f18f8Sesaxe  * Lookup table mapping hardware sharing relationships with hierarchy levels
111*fb2f18f8Sesaxe  */
112*fb2f18f8Sesaxe static int		pghw_level_table[PGHW_NUM_COMPONENTS];
113*fb2f18f8Sesaxe 
114*fb2f18f8Sesaxe /*
115*fb2f18f8Sesaxe  * Physical PG kstats
116*fb2f18f8Sesaxe  */
117*fb2f18f8Sesaxe struct pghw_kstat {
118*fb2f18f8Sesaxe 	kstat_named_t	pg_id;
119*fb2f18f8Sesaxe 	kstat_named_t	pg_class;
120*fb2f18f8Sesaxe 	kstat_named_t	pg_ncpus;
121*fb2f18f8Sesaxe 	kstat_named_t	pg_instance_id;
122*fb2f18f8Sesaxe 	kstat_named_t	pg_hw;
123*fb2f18f8Sesaxe } pghw_kstat = {
124*fb2f18f8Sesaxe 	{ "id",			KSTAT_DATA_UINT64 },
125*fb2f18f8Sesaxe 	{ "pg_class",		KSTAT_DATA_STRING },
126*fb2f18f8Sesaxe 	{ "ncpus",		KSTAT_DATA_UINT64 },
127*fb2f18f8Sesaxe 	{ "instance_id",	KSTAT_DATA_UINT64 },
128*fb2f18f8Sesaxe 	{ "hardware",		KSTAT_DATA_STRING },
129*fb2f18f8Sesaxe };
130*fb2f18f8Sesaxe 
131*fb2f18f8Sesaxe kmutex_t		pghw_kstat_lock;
132*fb2f18f8Sesaxe 
133*fb2f18f8Sesaxe /*
134*fb2f18f8Sesaxe  * hwset operations
135*fb2f18f8Sesaxe  */
136*fb2f18f8Sesaxe static group_t		*pghw_set_create(pghw_type_t);
137*fb2f18f8Sesaxe static void		pghw_set_add(group_t *, pghw_t *);
138*fb2f18f8Sesaxe static void		pghw_set_remove(group_t *, pghw_t *);
139*fb2f18f8Sesaxe 
140*fb2f18f8Sesaxe /*
141*fb2f18f8Sesaxe  * Initialize the physical portion of a physical PG
142*fb2f18f8Sesaxe  */
143*fb2f18f8Sesaxe void
144*fb2f18f8Sesaxe pghw_init(pghw_t *pg, cpu_t *cp, pghw_type_t hw)
145*fb2f18f8Sesaxe {
146*fb2f18f8Sesaxe 	group_t		*hwset;
147*fb2f18f8Sesaxe 
148*fb2f18f8Sesaxe 	if ((hwset = pghw_set_lookup(hw)) == NULL) {
149*fb2f18f8Sesaxe 		/*
150*fb2f18f8Sesaxe 		 * Haven't seen this hardware type yet
151*fb2f18f8Sesaxe 		 */
152*fb2f18f8Sesaxe 		hwset = pghw_set_create(hw);
153*fb2f18f8Sesaxe 	}
154*fb2f18f8Sesaxe 
155*fb2f18f8Sesaxe 	pghw_set_add(hwset, pg);
156*fb2f18f8Sesaxe 	pg->pghw_hw = hw;
157*fb2f18f8Sesaxe 	pg->pghw_instance =
158*fb2f18f8Sesaxe 	    pg_plat_hw_instance_id(cp, hw);
159*fb2f18f8Sesaxe 	pghw_kstat_create(pg);
160*fb2f18f8Sesaxe }
161*fb2f18f8Sesaxe 
162*fb2f18f8Sesaxe /*
163*fb2f18f8Sesaxe  * Teardown the physical portion of a physical PG
164*fb2f18f8Sesaxe  */
165*fb2f18f8Sesaxe void
166*fb2f18f8Sesaxe pghw_fini(pghw_t *pg)
167*fb2f18f8Sesaxe {
168*fb2f18f8Sesaxe 	group_t		*hwset;
169*fb2f18f8Sesaxe 
170*fb2f18f8Sesaxe 	hwset = pghw_set_lookup(pg->pghw_hw);
171*fb2f18f8Sesaxe 	ASSERT(hwset != NULL);
172*fb2f18f8Sesaxe 
173*fb2f18f8Sesaxe 	pghw_set_remove(hwset, pg);
174*fb2f18f8Sesaxe 	pg->pghw_instance = (id_t)PGHW_INSTANCE_ANON;
175*fb2f18f8Sesaxe 	pg->pghw_hw = (pghw_type_t)-1;
176*fb2f18f8Sesaxe 
177*fb2f18f8Sesaxe 	if (pg->pghw_kstat)
178*fb2f18f8Sesaxe 		kstat_delete(pg->pghw_kstat);
179*fb2f18f8Sesaxe }
180*fb2f18f8Sesaxe 
181*fb2f18f8Sesaxe /*
182*fb2f18f8Sesaxe  * Find an existing physical PG in which to place
183*fb2f18f8Sesaxe  * the given CPU for the specified hardware sharing
184*fb2f18f8Sesaxe  * relationship
185*fb2f18f8Sesaxe  */
186*fb2f18f8Sesaxe pghw_t *
187*fb2f18f8Sesaxe pghw_place_cpu(cpu_t *cp, pghw_type_t hw)
188*fb2f18f8Sesaxe {
189*fb2f18f8Sesaxe 	group_t		*hwset;
190*fb2f18f8Sesaxe 
191*fb2f18f8Sesaxe 	if ((hwset = pghw_set_lookup(hw)) == NULL) {
192*fb2f18f8Sesaxe 		return (NULL);
193*fb2f18f8Sesaxe 	}
194*fb2f18f8Sesaxe 
195*fb2f18f8Sesaxe 	return ((pghw_t *)pg_cpu_find_pg(cp, hwset));
196*fb2f18f8Sesaxe }
197*fb2f18f8Sesaxe 
198*fb2f18f8Sesaxe /*
199*fb2f18f8Sesaxe  * Find the pg representing the hw sharing relationship in which
200*fb2f18f8Sesaxe  * cp belongs
201*fb2f18f8Sesaxe  */
202*fb2f18f8Sesaxe pghw_t *
203*fb2f18f8Sesaxe pghw_find_pg(cpu_t *cp, pghw_type_t hw)
204*fb2f18f8Sesaxe {
205*fb2f18f8Sesaxe 	group_iter_t	i;
206*fb2f18f8Sesaxe 	pghw_t	*pg;
207*fb2f18f8Sesaxe 
208*fb2f18f8Sesaxe 	group_iter_init(&i);
209*fb2f18f8Sesaxe 	while ((pg = group_iterate(&cp->cpu_pg->pgs, &i)) != NULL) {
210*fb2f18f8Sesaxe 		if (pg->pghw_hw == hw)
211*fb2f18f8Sesaxe 			return (pg);
212*fb2f18f8Sesaxe 	}
213*fb2f18f8Sesaxe 	return (NULL);
214*fb2f18f8Sesaxe }
215*fb2f18f8Sesaxe 
216*fb2f18f8Sesaxe /*
217*fb2f18f8Sesaxe  * Find the PG of the given hardware sharing relationship
218*fb2f18f8Sesaxe  * type with the given instance id
219*fb2f18f8Sesaxe  */
220*fb2f18f8Sesaxe pghw_t *
221*fb2f18f8Sesaxe pghw_find_by_instance(id_t id, pghw_type_t hw)
222*fb2f18f8Sesaxe {
223*fb2f18f8Sesaxe 	group_iter_t	i;
224*fb2f18f8Sesaxe 	group_t		*set;
225*fb2f18f8Sesaxe 	pghw_t		*pg;
226*fb2f18f8Sesaxe 
227*fb2f18f8Sesaxe 	set = pghw_set_lookup(hw);
228*fb2f18f8Sesaxe 	if (!set)
229*fb2f18f8Sesaxe 		return (NULL);
230*fb2f18f8Sesaxe 
231*fb2f18f8Sesaxe 	group_iter_init(&i);
232*fb2f18f8Sesaxe 	while ((pg = group_iterate(set, &i)) != NULL) {
233*fb2f18f8Sesaxe 		if (pg->pghw_instance == id)
234*fb2f18f8Sesaxe 			return (pg);
235*fb2f18f8Sesaxe 	}
236*fb2f18f8Sesaxe 	return (NULL);
237*fb2f18f8Sesaxe }
238*fb2f18f8Sesaxe 
239*fb2f18f8Sesaxe /*
240*fb2f18f8Sesaxe  * CPUs physical ID cache creation / destruction
241*fb2f18f8Sesaxe  * The cache's elements are initialized to the CPU's id
242*fb2f18f8Sesaxe  */
243*fb2f18f8Sesaxe void
244*fb2f18f8Sesaxe pghw_physid_create(cpu_t *cp)
245*fb2f18f8Sesaxe {
246*fb2f18f8Sesaxe 	int	i;
247*fb2f18f8Sesaxe 
248*fb2f18f8Sesaxe 	cp->cpu_physid = kmem_alloc(sizeof (cpu_physid_t), KM_SLEEP);
249*fb2f18f8Sesaxe 
250*fb2f18f8Sesaxe 	for (i = 0; i < (sizeof (cpu_physid_t) / sizeof (id_t)); i++) {
251*fb2f18f8Sesaxe 		((id_t *)cp->cpu_physid)[i] = cp->cpu_id;
252*fb2f18f8Sesaxe 	}
253*fb2f18f8Sesaxe }
254*fb2f18f8Sesaxe 
255*fb2f18f8Sesaxe void
256*fb2f18f8Sesaxe pghw_physid_destroy(cpu_t *cp)
257*fb2f18f8Sesaxe {
258*fb2f18f8Sesaxe 	if (cp->cpu_physid) {
259*fb2f18f8Sesaxe 		kmem_free(cp->cpu_physid, sizeof (cpu_physid_t));
260*fb2f18f8Sesaxe 		cp->cpu_physid = NULL;
261*fb2f18f8Sesaxe 	}
262*fb2f18f8Sesaxe }
263*fb2f18f8Sesaxe 
264*fb2f18f8Sesaxe /*
265*fb2f18f8Sesaxe  * Return a sequential level identifier for the specified
266*fb2f18f8Sesaxe  * hardware sharing relationship
267*fb2f18f8Sesaxe  */
268*fb2f18f8Sesaxe int
269*fb2f18f8Sesaxe pghw_level(pghw_type_t hw)
270*fb2f18f8Sesaxe {
271*fb2f18f8Sesaxe 	return (pg_plat_hw_level(hw));
272*fb2f18f8Sesaxe }
273*fb2f18f8Sesaxe 
274*fb2f18f8Sesaxe /*
275*fb2f18f8Sesaxe  * Create a new, empty hwset.
276*fb2f18f8Sesaxe  * This routine may block, and must not be called from any
277*fb2f18f8Sesaxe  * paused CPU context.
278*fb2f18f8Sesaxe  */
279*fb2f18f8Sesaxe static group_t	*
280*fb2f18f8Sesaxe pghw_set_create(pghw_type_t hw)
281*fb2f18f8Sesaxe {
282*fb2f18f8Sesaxe 	group_t	*g;
283*fb2f18f8Sesaxe 	int	ret;
284*fb2f18f8Sesaxe 
285*fb2f18f8Sesaxe 	/*
286*fb2f18f8Sesaxe 	 * Create the top level PG hw group if it doesn't already exist
287*fb2f18f8Sesaxe 	 * This is a "set" of hardware sets, that is ordered (and indexed)
288*fb2f18f8Sesaxe 	 * by the pghw_type_t enum.
289*fb2f18f8Sesaxe 	 */
290*fb2f18f8Sesaxe 	if (pg_hw == NULL) {
291*fb2f18f8Sesaxe 		pg_hw = kmem_alloc(sizeof (group_t), KM_SLEEP);
292*fb2f18f8Sesaxe 		group_create(pg_hw);
293*fb2f18f8Sesaxe 		group_expand(pg_hw, (uint_t)PGHW_NUM_COMPONENTS);
294*fb2f18f8Sesaxe 	}
295*fb2f18f8Sesaxe 
296*fb2f18f8Sesaxe 	/*
297*fb2f18f8Sesaxe 	 * Create the new hwset
298*fb2f18f8Sesaxe 	 * Add it to the top level pg_hw group.
299*fb2f18f8Sesaxe 	 */
300*fb2f18f8Sesaxe 	g = kmem_alloc(sizeof (group_t), KM_SLEEP);
301*fb2f18f8Sesaxe 	group_create(g);
302*fb2f18f8Sesaxe 
303*fb2f18f8Sesaxe 	ret = group_add_at(pg_hw, g, (uint_t)hw);
304*fb2f18f8Sesaxe 	ASSERT(ret == 0);
305*fb2f18f8Sesaxe 
306*fb2f18f8Sesaxe 	/*
307*fb2f18f8Sesaxe 	 * Update the table that maps hardware sharing relationships
308*fb2f18f8Sesaxe 	 * to hierarchy levels
309*fb2f18f8Sesaxe 	 */
310*fb2f18f8Sesaxe 	ASSERT(pghw_level_table[hw] == NULL);
311*fb2f18f8Sesaxe 	pghw_level_table[hw] = pg_plat_hw_level(hw);
312*fb2f18f8Sesaxe 
313*fb2f18f8Sesaxe 	return (g);
314*fb2f18f8Sesaxe }
315*fb2f18f8Sesaxe 
316*fb2f18f8Sesaxe /*
317*fb2f18f8Sesaxe  * Find the hwset associated with the given hardware sharing type
318*fb2f18f8Sesaxe  */
319*fb2f18f8Sesaxe group_t *
320*fb2f18f8Sesaxe pghw_set_lookup(pghw_type_t hw)
321*fb2f18f8Sesaxe {
322*fb2f18f8Sesaxe 	group_t	*hwset;
323*fb2f18f8Sesaxe 
324*fb2f18f8Sesaxe 	if (pg_hw == NULL)
325*fb2f18f8Sesaxe 		return (NULL);
326*fb2f18f8Sesaxe 
327*fb2f18f8Sesaxe 	hwset = GROUP_ACCESS(pg_hw, (uint_t)hw);
328*fb2f18f8Sesaxe 	return (hwset);
329*fb2f18f8Sesaxe }
330*fb2f18f8Sesaxe 
331*fb2f18f8Sesaxe /*
332*fb2f18f8Sesaxe  * Add a PG to a hwset
333*fb2f18f8Sesaxe  */
334*fb2f18f8Sesaxe static void
335*fb2f18f8Sesaxe pghw_set_add(group_t *hwset, pghw_t *pg)
336*fb2f18f8Sesaxe {
337*fb2f18f8Sesaxe 	(void) group_add(hwset, pg, GRP_RESIZE);
338*fb2f18f8Sesaxe }
339*fb2f18f8Sesaxe 
340*fb2f18f8Sesaxe /*
341*fb2f18f8Sesaxe  * Remove a PG from a hwset
342*fb2f18f8Sesaxe  */
343*fb2f18f8Sesaxe static void
344*fb2f18f8Sesaxe pghw_set_remove(group_t *hwset, pghw_t *pg)
345*fb2f18f8Sesaxe {
346*fb2f18f8Sesaxe 	int result;
347*fb2f18f8Sesaxe 
348*fb2f18f8Sesaxe 	result = group_remove(hwset, pg, GRP_RESIZE);
349*fb2f18f8Sesaxe 	ASSERT(result == 0);
350*fb2f18f8Sesaxe }
351*fb2f18f8Sesaxe 
352*fb2f18f8Sesaxe 
353*fb2f18f8Sesaxe /*
354*fb2f18f8Sesaxe  * Return a string name given a pg_hw sharing type
355*fb2f18f8Sesaxe  */
356*fb2f18f8Sesaxe #define	PGHW_TYPE_NAME_MAX	8
357*fb2f18f8Sesaxe 
358*fb2f18f8Sesaxe static char *
359*fb2f18f8Sesaxe pghw_type_string(pghw_type_t hw)
360*fb2f18f8Sesaxe {
361*fb2f18f8Sesaxe 	switch (hw) {
362*fb2f18f8Sesaxe 	case PGHW_IPIPE:
363*fb2f18f8Sesaxe 		return ("ipipe");
364*fb2f18f8Sesaxe 	case PGHW_CACHE:
365*fb2f18f8Sesaxe 		return ("cache");
366*fb2f18f8Sesaxe 	case PGHW_FPU:
367*fb2f18f8Sesaxe 		return ("fpu");
368*fb2f18f8Sesaxe 	case PGHW_CHIP:
369*fb2f18f8Sesaxe 		return ("chip");
370*fb2f18f8Sesaxe 	case PGHW_MEMORY:
371*fb2f18f8Sesaxe 		return ("memory");
372*fb2f18f8Sesaxe 	default:
373*fb2f18f8Sesaxe 		return ("unknown");
374*fb2f18f8Sesaxe 	}
375*fb2f18f8Sesaxe }
376*fb2f18f8Sesaxe 
377*fb2f18f8Sesaxe /*
378*fb2f18f8Sesaxe  * Create / Update routines for PG hw kstats
379*fb2f18f8Sesaxe  *
380*fb2f18f8Sesaxe  * It is the intention of these kstats to provide some level
381*fb2f18f8Sesaxe  * of informational / debugging observability into the types
382*fb2f18f8Sesaxe  * and nature of the system's detected hardware sharing relationships
383*fb2f18f8Sesaxe  */
384*fb2f18f8Sesaxe void
385*fb2f18f8Sesaxe pghw_kstat_create(pghw_t *pg)
386*fb2f18f8Sesaxe {
387*fb2f18f8Sesaxe 	/*
388*fb2f18f8Sesaxe 	 * Create a physical pg kstat
389*fb2f18f8Sesaxe 	 */
390*fb2f18f8Sesaxe 	if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id,
391*fb2f18f8Sesaxe 	    "pg", "pg", KSTAT_TYPE_NAMED,
392*fb2f18f8Sesaxe 	    sizeof (pghw_kstat) / sizeof (kstat_named_t),
393*fb2f18f8Sesaxe 	    KSTAT_FLAG_VIRTUAL)) != NULL) {
394*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_data_size += PG_CLASS_NAME_MAX;
395*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_data_size += PGHW_TYPE_NAME_MAX;
396*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_lock = &pghw_kstat_lock;
397*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_data = &pghw_kstat;
398*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_update = pghw_kstat_update;
399*fb2f18f8Sesaxe 		pg->pghw_kstat->ks_private = pg;
400*fb2f18f8Sesaxe 		kstat_install(pg->pghw_kstat);
401*fb2f18f8Sesaxe 	}
402*fb2f18f8Sesaxe }
403*fb2f18f8Sesaxe 
404*fb2f18f8Sesaxe int
405*fb2f18f8Sesaxe pghw_kstat_update(kstat_t *ksp, int rw)
406*fb2f18f8Sesaxe {
407*fb2f18f8Sesaxe 	struct pghw_kstat	*pgsp = &pghw_kstat;
408*fb2f18f8Sesaxe 	pghw_t			*pg = ksp->ks_private;
409*fb2f18f8Sesaxe 
410*fb2f18f8Sesaxe 	if (rw == KSTAT_WRITE)
411*fb2f18f8Sesaxe 		return (EACCES);
412*fb2f18f8Sesaxe 
413*fb2f18f8Sesaxe 	pgsp->pg_id.value.ui64 = ((pg_t *)pg)->pg_id;
414*fb2f18f8Sesaxe 	pgsp->pg_ncpus.value.ui64 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
415*fb2f18f8Sesaxe 	pgsp->pg_instance_id.value.ui64 = (uint64_t)pg->pghw_instance;
416*fb2f18f8Sesaxe 	kstat_named_setstr(&pgsp->pg_class, ((pg_t *)pg)->pg_class->pgc_name);
417*fb2f18f8Sesaxe 	kstat_named_setstr(&pgsp->pg_hw, pghw_type_string(pg->pghw_hw));
418*fb2f18f8Sesaxe 
419*fb2f18f8Sesaxe 	return (0);
420*fb2f18f8Sesaxe }
421