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 /*
22*d3c97224SAlexander Kolbasov * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23fb2f18f8Sesaxe */
24fb2f18f8Sesaxe
25fb2f18f8Sesaxe #include <sys/systm.h>
26fb2f18f8Sesaxe #include <sys/types.h>
27fb2f18f8Sesaxe #include <sys/param.h>
28fb2f18f8Sesaxe #include <sys/thread.h>
29fb2f18f8Sesaxe #include <sys/cpuvar.h>
30fb2f18f8Sesaxe #include <sys/kmem.h>
31fb2f18f8Sesaxe #include <sys/cmn_err.h>
32*d3c97224SAlexander Kolbasov #include <sys/policy.h>
33fb2f18f8Sesaxe #include <sys/group.h>
34fb2f18f8Sesaxe #include <sys/pg.h>
35fb2f18f8Sesaxe #include <sys/pghw.h>
360e751525SEric Saxe #include <sys/cpu_pm.h>
37b885580bSAlexander Kolbasov #include <sys/cap_util.h>
38fb2f18f8Sesaxe
39fb2f18f8Sesaxe /*
40fb2f18f8Sesaxe * Processor Groups: Hardware sharing relationship layer
41fb2f18f8Sesaxe *
42fb2f18f8Sesaxe * This file implements an extension to Processor Groups to capture
43fb2f18f8Sesaxe * hardware sharing relationships existing between logical CPUs. Examples of
44fb2f18f8Sesaxe * hardware sharing relationships include shared caches on some CMT
45fb2f18f8Sesaxe * procesoor architectures, or shared local memory controllers on NUMA
46fb2f18f8Sesaxe * based system architectures.
47fb2f18f8Sesaxe *
48fb2f18f8Sesaxe * The pghw_t structure represents the extended PG. The first member
49fb2f18f8Sesaxe * of the structure is the generic pg_t with the pghw specific members
50fb2f18f8Sesaxe * following. The generic pg_t *must* remain the first member of the
51fb2f18f8Sesaxe * structure as the code uses casting of structure references to access
52fb2f18f8Sesaxe * the generic pg_t structure elements.
53fb2f18f8Sesaxe *
54fb2f18f8Sesaxe * In addition to the generic CPU grouping, physical PGs have a hardware
55fb2f18f8Sesaxe * sharing relationship enumerated "type", and an instance id. The enumerated
56fb2f18f8Sesaxe * type is defined by the pghw_type_t enumeration, while the instance id
57fb2f18f8Sesaxe * uniquely identifies the sharing instance from among others of the same
58fb2f18f8Sesaxe * hardware sharing type.
59fb2f18f8Sesaxe *
60fb2f18f8Sesaxe * The physical PGs are organized into an overall hierarchy, and are tracked
61fb2f18f8Sesaxe * in a number of different per CPU, and per pghw_type_t type groups.
62fb2f18f8Sesaxe * As an example:
63fb2f18f8Sesaxe *
64fb2f18f8Sesaxe * -------------
65fb2f18f8Sesaxe * | pg_hw |
66fb2f18f8Sesaxe * | (group_t) |
67fb2f18f8Sesaxe * -------------
68fb2f18f8Sesaxe * || ============================
69fb2f18f8Sesaxe * ||\\-----------------------// \\ \\
70fb2f18f8Sesaxe * || | hwset (PGC_HW_CHIP) | ------------- -------------
71fb2f18f8Sesaxe * || | (group_t) | | pghw_t | | pghw_t |
72fb2f18f8Sesaxe * || ----------------------- | chip 0 | | chip 1 |
73fb2f18f8Sesaxe * || ------------- -------------
74fb2f18f8Sesaxe * || \\ \\ \\ \\ \\ \\ \\ \\
75fb2f18f8Sesaxe * || cpu cpu cpu cpu cpu cpu cpu cpu
76fb2f18f8Sesaxe * ||
77fb2f18f8Sesaxe * || ============================
78fb2f18f8Sesaxe * ||\\-----------------------// \\ \\
79fb2f18f8Sesaxe * || | hwset (PGC_HW_IPIPE)| ------------- -------------
80fb2f18f8Sesaxe * || | (group_t) | | pghw_t | | pghw_t |
81fb2f18f8Sesaxe * || ----------------------- | ipipe 0 | | ipipe 1 |
82fb2f18f8Sesaxe * || ------------- -------------
83fb2f18f8Sesaxe * || \\ \\ \\ \\
84fb2f18f8Sesaxe * || cpu cpu cpu cpu
85fb2f18f8Sesaxe * ...
86fb2f18f8Sesaxe *
87fb2f18f8Sesaxe *
88fb2f18f8Sesaxe * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group
89fb2f18f8Sesaxe * of physical PGs of the same hardware sharing type. Within each hwset, the
90fb2f18f8Sesaxe * PG's instance id uniquely identifies the grouping relationshsip among other
91fb2f18f8Sesaxe * groupings of the same sharing type. The instance id for a grouping is
92fb2f18f8Sesaxe * platform defined, and in some cases may be used by platform code as a handle
93fb2f18f8Sesaxe * to search for a particular relationship instance.
94fb2f18f8Sesaxe *
95fb2f18f8Sesaxe * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs
96fb2f18f8Sesaxe * that participate in the sharing relationship. Each CPU also has associated
97fb2f18f8Sesaxe * with it a grouping tracking the PGs in which the CPU belongs. This can be
98fb2f18f8Sesaxe * used to iterate over the various relationships in which the CPU participates
99fb2f18f8Sesaxe * (the CPU's chip, cache, lgroup, etc.).
100fb2f18f8Sesaxe *
101fb2f18f8Sesaxe * The hwsets are created dynamically as new hardware sharing relationship types
1020e751525SEric Saxe * are instantiated. They are never destroyed, as once a given relationship
103fb2f18f8Sesaxe * type appears in the system, it is quite likely that at least one instance of
104fb2f18f8Sesaxe * that relationship will always persist as long as the system is running.
105fb2f18f8Sesaxe */
106fb2f18f8Sesaxe
107fb2f18f8Sesaxe static group_t *pg_hw; /* top level pg hw group */
108fb2f18f8Sesaxe
109fb2f18f8Sesaxe /*
110fb2f18f8Sesaxe * Physical PG kstats
111fb2f18f8Sesaxe */
112fb2f18f8Sesaxe struct pghw_kstat {
113fb2f18f8Sesaxe kstat_named_t pg_id;
114fb2f18f8Sesaxe kstat_named_t pg_class;
115fb2f18f8Sesaxe kstat_named_t pg_ncpus;
116fb2f18f8Sesaxe kstat_named_t pg_instance_id;
117fb2f18f8Sesaxe kstat_named_t pg_hw;
1180e751525SEric Saxe kstat_named_t pg_policy;
119fb2f18f8Sesaxe } pghw_kstat = {
120*d3c97224SAlexander Kolbasov { "id", KSTAT_DATA_INT32 },
121fb2f18f8Sesaxe { "pg_class", KSTAT_DATA_STRING },
122b885580bSAlexander Kolbasov { "ncpus", KSTAT_DATA_UINT32 },
123b885580bSAlexander Kolbasov { "instance_id", KSTAT_DATA_UINT32 },
124fb2f18f8Sesaxe { "hardware", KSTAT_DATA_STRING },
1250e751525SEric Saxe { "policy", KSTAT_DATA_STRING },
126fb2f18f8Sesaxe };
127fb2f18f8Sesaxe
128fb2f18f8Sesaxe kmutex_t pghw_kstat_lock;
129fb2f18f8Sesaxe
130fb2f18f8Sesaxe /*
131b885580bSAlexander Kolbasov * Capacity and Utilization PG kstats
132b885580bSAlexander Kolbasov *
133b885580bSAlexander Kolbasov * These kstats are updated one at a time, so we can have a single scratch space
134b885580bSAlexander Kolbasov * to fill the data.
135b885580bSAlexander Kolbasov *
136b885580bSAlexander Kolbasov * kstat fields:
137b885580bSAlexander Kolbasov *
138*d3c97224SAlexander Kolbasov * pg_id PG ID for PG described by this kstat
139*d3c97224SAlexander Kolbasov *
140*d3c97224SAlexander Kolbasov * pg_parent Parent PG ID. The value -1 means "no parent".
141b885580bSAlexander Kolbasov *
142b885580bSAlexander Kolbasov * pg_ncpus Number of CPUs within this PG
143b885580bSAlexander Kolbasov *
144b885580bSAlexander Kolbasov * pg_cpus String describing CPUs within this PG
145b885580bSAlexander Kolbasov *
146*d3c97224SAlexander Kolbasov * pg_relationship Name of sharing relationship for this PG
147b885580bSAlexander Kolbasov *
148b885580bSAlexander Kolbasov * pg_generation Generation value that increases whenever any CPU leaves
149b885580bSAlexander Kolbasov * or joins PG. Two kstat snapshots for the same
150b885580bSAlexander Kolbasov * CPU may only be compared if they have the same
151b885580bSAlexander Kolbasov * generation
152b885580bSAlexander Kolbasov *
153b885580bSAlexander Kolbasov * pg_hw_util Running value of PG utilization for the sharing
154b885580bSAlexander Kolbasov * relationship
155b885580bSAlexander Kolbasov *
156b885580bSAlexander Kolbasov * pg_hw_util_time_running
157b885580bSAlexander Kolbasov * Total time spent collecting CU data. The time may be
158b885580bSAlexander Kolbasov * less than wall time if CU counters were stopped for
159b885580bSAlexander Kolbasov * some time.
160b885580bSAlexander Kolbasov *
161b885580bSAlexander Kolbasov * pg_hw_util_time_stopped Total time the CU counters were stopped.
162b885580bSAlexander Kolbasov *
163b885580bSAlexander Kolbasov * pg_hw_util_rate Utilization rate, expressed in operations per second.
164b885580bSAlexander Kolbasov *
165b885580bSAlexander Kolbasov * pg_hw_util_rate_max Maximum observed value of utilization rate.
166b885580bSAlexander Kolbasov */
167b885580bSAlexander Kolbasov struct pghw_cu_kstat {
168b885580bSAlexander Kolbasov kstat_named_t pg_id;
169*d3c97224SAlexander Kolbasov kstat_named_t pg_parent_id;
170b885580bSAlexander Kolbasov kstat_named_t pg_ncpus;
171b885580bSAlexander Kolbasov kstat_named_t pg_generation;
172b885580bSAlexander Kolbasov kstat_named_t pg_hw_util;
173b885580bSAlexander Kolbasov kstat_named_t pg_hw_util_time_running;
174b885580bSAlexander Kolbasov kstat_named_t pg_hw_util_time_stopped;
175b885580bSAlexander Kolbasov kstat_named_t pg_hw_util_rate;
176b885580bSAlexander Kolbasov kstat_named_t pg_hw_util_rate_max;
177b885580bSAlexander Kolbasov kstat_named_t pg_cpus;
178*d3c97224SAlexander Kolbasov kstat_named_t pg_relationship;
179b885580bSAlexander Kolbasov } pghw_cu_kstat = {
180*d3c97224SAlexander Kolbasov { "pg_id", KSTAT_DATA_INT32 },
181*d3c97224SAlexander Kolbasov { "parent_pg_id", KSTAT_DATA_INT32 },
182b885580bSAlexander Kolbasov { "ncpus", KSTAT_DATA_UINT32 },
183b885580bSAlexander Kolbasov { "generation", KSTAT_DATA_UINT32 },
184b885580bSAlexander Kolbasov { "hw_util", KSTAT_DATA_UINT64 },
185b885580bSAlexander Kolbasov { "hw_util_time_running", KSTAT_DATA_UINT64 },
186b885580bSAlexander Kolbasov { "hw_util_time_stopped", KSTAT_DATA_UINT64 },
187b885580bSAlexander Kolbasov { "hw_util_rate", KSTAT_DATA_UINT64 },
188b885580bSAlexander Kolbasov { "hw_util_rate_max", KSTAT_DATA_UINT64 },
189b885580bSAlexander Kolbasov { "cpus", KSTAT_DATA_STRING },
190*d3c97224SAlexander Kolbasov { "relationship", KSTAT_DATA_STRING },
191b885580bSAlexander Kolbasov };
192b885580bSAlexander Kolbasov
193b885580bSAlexander Kolbasov /*
194b885580bSAlexander Kolbasov * Calculate the string size to represent NCPUS. Allow 5 digits for each CPU ID
195b885580bSAlexander Kolbasov * plus one space per CPU plus NUL byte in the end. This is only an estimate,
196b885580bSAlexander Kolbasov * since we try to compress CPU ranges as x-y. In the worst case the string
197b885580bSAlexander Kolbasov * representation of CPUs may be truncated.
198b885580bSAlexander Kolbasov */
199b885580bSAlexander Kolbasov #define CPUSTR_LEN(ncpus) ((ncpus) * 6)
200b885580bSAlexander Kolbasov
201b885580bSAlexander Kolbasov /*
202b885580bSAlexander Kolbasov * Maximum length of the string that represents list of CPUs
203b885580bSAlexander Kolbasov */
204b885580bSAlexander Kolbasov static int pg_cpulist_maxlen = 0;
205b885580bSAlexander Kolbasov
206b885580bSAlexander Kolbasov static void pghw_kstat_create(pghw_t *);
207b885580bSAlexander Kolbasov static int pghw_kstat_update(kstat_t *, int);
208b885580bSAlexander Kolbasov static int pghw_cu_kstat_update(kstat_t *, int);
209b885580bSAlexander Kolbasov static int cpu2id(void *);
210b885580bSAlexander Kolbasov
211b885580bSAlexander Kolbasov /*
212fb2f18f8Sesaxe * hwset operations
213fb2f18f8Sesaxe */
214fb2f18f8Sesaxe static group_t *pghw_set_create(pghw_type_t);
215fb2f18f8Sesaxe static void pghw_set_add(group_t *, pghw_t *);
216fb2f18f8Sesaxe static void pghw_set_remove(group_t *, pghw_t *);
217fb2f18f8Sesaxe
218b885580bSAlexander Kolbasov static void pghw_cpulist_alloc(pghw_t *);
219b885580bSAlexander Kolbasov static int cpu2id(void *);
220*d3c97224SAlexander Kolbasov static pgid_t pghw_parent_id(pghw_t *);
221b885580bSAlexander Kolbasov
222fb2f18f8Sesaxe /*
2230e751525SEric Saxe * Initialize the physical portion of a hardware PG
224fb2f18f8Sesaxe */
225fb2f18f8Sesaxe void
pghw_init(pghw_t * pg,cpu_t * cp,pghw_type_t hw)226fb2f18f8Sesaxe pghw_init(pghw_t *pg, cpu_t *cp, pghw_type_t hw)
227fb2f18f8Sesaxe {
228fb2f18f8Sesaxe group_t *hwset;
229fb2f18f8Sesaxe
230fb2f18f8Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) {
231fb2f18f8Sesaxe /*
232fb2f18f8Sesaxe * Haven't seen this hardware type yet
233fb2f18f8Sesaxe */
234fb2f18f8Sesaxe hwset = pghw_set_create(hw);
235fb2f18f8Sesaxe }
236fb2f18f8Sesaxe
237fb2f18f8Sesaxe pghw_set_add(hwset, pg);
238fb2f18f8Sesaxe pg->pghw_hw = hw;
239b885580bSAlexander Kolbasov pg->pghw_generation = 0;
240fb2f18f8Sesaxe pg->pghw_instance =
241fb2f18f8Sesaxe pg_plat_hw_instance_id(cp, hw);
242fb2f18f8Sesaxe pghw_kstat_create(pg);
2430e751525SEric Saxe
2440e751525SEric Saxe /*
2450e751525SEric Saxe * Hardware sharing relationship specific initialization
2460e751525SEric Saxe */
2470e751525SEric Saxe switch (pg->pghw_hw) {
2480e751525SEric Saxe case PGHW_POW_ACTIVE:
2490e751525SEric Saxe pg->pghw_handle =
2500e751525SEric Saxe (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_ACTIVE);
2510e751525SEric Saxe break;
2520e751525SEric Saxe case PGHW_POW_IDLE:
2530e751525SEric Saxe pg->pghw_handle =
2540e751525SEric Saxe (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_IDLE);
2550e751525SEric Saxe break;
2560e751525SEric Saxe default:
2570e751525SEric Saxe pg->pghw_handle = (pghw_handle_t)NULL;
2580e751525SEric Saxe }
259fb2f18f8Sesaxe }
260fb2f18f8Sesaxe
261fb2f18f8Sesaxe /*
262fb2f18f8Sesaxe * Teardown the physical portion of a physical PG
263fb2f18f8Sesaxe */
264fb2f18f8Sesaxe void
pghw_fini(pghw_t * pg)265fb2f18f8Sesaxe pghw_fini(pghw_t *pg)
266fb2f18f8Sesaxe {
267fb2f18f8Sesaxe group_t *hwset;
268fb2f18f8Sesaxe
269*d3c97224SAlexander Kolbasov pghw_cmt_fini(pg);
270*d3c97224SAlexander Kolbasov
271fb2f18f8Sesaxe hwset = pghw_set_lookup(pg->pghw_hw);
272fb2f18f8Sesaxe ASSERT(hwset != NULL);
273fb2f18f8Sesaxe
274fb2f18f8Sesaxe pghw_set_remove(hwset, pg);
275fb2f18f8Sesaxe pg->pghw_instance = (id_t)PGHW_INSTANCE_ANON;
276fb2f18f8Sesaxe pg->pghw_hw = (pghw_type_t)-1;
277fb2f18f8Sesaxe
278b885580bSAlexander Kolbasov if (pg->pghw_kstat != NULL)
279fb2f18f8Sesaxe kstat_delete(pg->pghw_kstat);
280b885580bSAlexander Kolbasov
281*d3c97224SAlexander Kolbasov }
282*d3c97224SAlexander Kolbasov
283*d3c97224SAlexander Kolbasov /*
284*d3c97224SAlexander Kolbasov * PG is removed from CMT hierarchy
285*d3c97224SAlexander Kolbasov */
286*d3c97224SAlexander Kolbasov void
pghw_cmt_fini(pghw_t * pg)287*d3c97224SAlexander Kolbasov pghw_cmt_fini(pghw_t *pg)
288*d3c97224SAlexander Kolbasov {
289b885580bSAlexander Kolbasov /*
290b885580bSAlexander Kolbasov * Destroy string representation of CPUs
291b885580bSAlexander Kolbasov */
292b885580bSAlexander Kolbasov if (pg->pghw_cpulist != NULL) {
293b885580bSAlexander Kolbasov kmem_free(pg->pghw_cpulist,
294b885580bSAlexander Kolbasov pg->pghw_cpulist_len);
295b885580bSAlexander Kolbasov pg->pghw_cpulist = NULL;
296b885580bSAlexander Kolbasov }
297b885580bSAlexander Kolbasov
298*d3c97224SAlexander Kolbasov /*
299*d3c97224SAlexander Kolbasov * Destroy CU kstats
300*d3c97224SAlexander Kolbasov */
301*d3c97224SAlexander Kolbasov if (pg->pghw_cu_kstat != NULL) {
302b885580bSAlexander Kolbasov kstat_delete(pg->pghw_cu_kstat);
303*d3c97224SAlexander Kolbasov pg->pghw_cu_kstat = NULL;
304*d3c97224SAlexander Kolbasov }
305fb2f18f8Sesaxe }
306fb2f18f8Sesaxe
307fb2f18f8Sesaxe /*
308fb2f18f8Sesaxe * Find an existing physical PG in which to place
309fb2f18f8Sesaxe * the given CPU for the specified hardware sharing
310fb2f18f8Sesaxe * relationship
311fb2f18f8Sesaxe */
312fb2f18f8Sesaxe pghw_t *
pghw_place_cpu(cpu_t * cp,pghw_type_t hw)313fb2f18f8Sesaxe pghw_place_cpu(cpu_t *cp, pghw_type_t hw)
314fb2f18f8Sesaxe {
315fb2f18f8Sesaxe group_t *hwset;
316fb2f18f8Sesaxe
317fb2f18f8Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) {
318fb2f18f8Sesaxe return (NULL);
319fb2f18f8Sesaxe }
320fb2f18f8Sesaxe
321fb2f18f8Sesaxe return ((pghw_t *)pg_cpu_find_pg(cp, hwset));
322fb2f18f8Sesaxe }
323fb2f18f8Sesaxe
324fb2f18f8Sesaxe /*
325fb2f18f8Sesaxe * Find the pg representing the hw sharing relationship in which
326fb2f18f8Sesaxe * cp belongs
327fb2f18f8Sesaxe */
328fb2f18f8Sesaxe pghw_t *
pghw_find_pg(cpu_t * cp,pghw_type_t hw)329fb2f18f8Sesaxe pghw_find_pg(cpu_t *cp, pghw_type_t hw)
330fb2f18f8Sesaxe {
331fb2f18f8Sesaxe group_iter_t i;
332fb2f18f8Sesaxe pghw_t *pg;
333fb2f18f8Sesaxe
334fb2f18f8Sesaxe group_iter_init(&i);
335fb2f18f8Sesaxe while ((pg = group_iterate(&cp->cpu_pg->pgs, &i)) != NULL) {
336fb2f18f8Sesaxe if (pg->pghw_hw == hw)
337fb2f18f8Sesaxe return (pg);
338fb2f18f8Sesaxe }
339fb2f18f8Sesaxe return (NULL);
340fb2f18f8Sesaxe }
341fb2f18f8Sesaxe
342fb2f18f8Sesaxe /*
343fb2f18f8Sesaxe * Find the PG of the given hardware sharing relationship
344fb2f18f8Sesaxe * type with the given instance id
345fb2f18f8Sesaxe */
346fb2f18f8Sesaxe pghw_t *
pghw_find_by_instance(id_t id,pghw_type_t hw)347fb2f18f8Sesaxe pghw_find_by_instance(id_t id, pghw_type_t hw)
348fb2f18f8Sesaxe {
349fb2f18f8Sesaxe group_iter_t i;
350fb2f18f8Sesaxe group_t *set;
351fb2f18f8Sesaxe pghw_t *pg;
352fb2f18f8Sesaxe
353fb2f18f8Sesaxe set = pghw_set_lookup(hw);
354fb2f18f8Sesaxe if (!set)
355fb2f18f8Sesaxe return (NULL);
356fb2f18f8Sesaxe
357fb2f18f8Sesaxe group_iter_init(&i);
358fb2f18f8Sesaxe while ((pg = group_iterate(set, &i)) != NULL) {
359fb2f18f8Sesaxe if (pg->pghw_instance == id)
360fb2f18f8Sesaxe return (pg);
361fb2f18f8Sesaxe }
362fb2f18f8Sesaxe return (NULL);
363fb2f18f8Sesaxe }
364fb2f18f8Sesaxe
365fb2f18f8Sesaxe /*
366fb2f18f8Sesaxe * CPUs physical ID cache creation / destruction
367fb2f18f8Sesaxe * The cache's elements are initialized to the CPU's id
368fb2f18f8Sesaxe */
369fb2f18f8Sesaxe void
pghw_physid_create(cpu_t * cp)370fb2f18f8Sesaxe pghw_physid_create(cpu_t *cp)
371fb2f18f8Sesaxe {
372fb2f18f8Sesaxe int i;
373fb2f18f8Sesaxe
374fb2f18f8Sesaxe cp->cpu_physid = kmem_alloc(sizeof (cpu_physid_t), KM_SLEEP);
375fb2f18f8Sesaxe
376fb2f18f8Sesaxe for (i = 0; i < (sizeof (cpu_physid_t) / sizeof (id_t)); i++) {
377fb2f18f8Sesaxe ((id_t *)cp->cpu_physid)[i] = cp->cpu_id;
378fb2f18f8Sesaxe }
379fb2f18f8Sesaxe }
380fb2f18f8Sesaxe
381fb2f18f8Sesaxe void
pghw_physid_destroy(cpu_t * cp)382fb2f18f8Sesaxe pghw_physid_destroy(cpu_t *cp)
383fb2f18f8Sesaxe {
384fb2f18f8Sesaxe if (cp->cpu_physid) {
385fb2f18f8Sesaxe kmem_free(cp->cpu_physid, sizeof (cpu_physid_t));
386fb2f18f8Sesaxe cp->cpu_physid = NULL;
387fb2f18f8Sesaxe }
388fb2f18f8Sesaxe }
389fb2f18f8Sesaxe
390fb2f18f8Sesaxe /*
391fb2f18f8Sesaxe * Create a new, empty hwset.
392fb2f18f8Sesaxe * This routine may block, and must not be called from any
393fb2f18f8Sesaxe * paused CPU context.
394fb2f18f8Sesaxe */
395fb2f18f8Sesaxe static group_t *
pghw_set_create(pghw_type_t hw)396fb2f18f8Sesaxe pghw_set_create(pghw_type_t hw)
397fb2f18f8Sesaxe {
398fb2f18f8Sesaxe group_t *g;
399fb2f18f8Sesaxe int ret;
400fb2f18f8Sesaxe
401fb2f18f8Sesaxe /*
402fb2f18f8Sesaxe * Create the top level PG hw group if it doesn't already exist
403fb2f18f8Sesaxe * This is a "set" of hardware sets, that is ordered (and indexed)
404fb2f18f8Sesaxe * by the pghw_type_t enum.
405fb2f18f8Sesaxe */
406fb2f18f8Sesaxe if (pg_hw == NULL) {
407fb2f18f8Sesaxe pg_hw = kmem_alloc(sizeof (group_t), KM_SLEEP);
408fb2f18f8Sesaxe group_create(pg_hw);
409fb2f18f8Sesaxe group_expand(pg_hw, (uint_t)PGHW_NUM_COMPONENTS);
410fb2f18f8Sesaxe }
411fb2f18f8Sesaxe
412fb2f18f8Sesaxe /*
413fb2f18f8Sesaxe * Create the new hwset
414fb2f18f8Sesaxe * Add it to the top level pg_hw group.
415fb2f18f8Sesaxe */
416fb2f18f8Sesaxe g = kmem_alloc(sizeof (group_t), KM_SLEEP);
417fb2f18f8Sesaxe group_create(g);
418fb2f18f8Sesaxe
419fb2f18f8Sesaxe ret = group_add_at(pg_hw, g, (uint_t)hw);
420fb2f18f8Sesaxe ASSERT(ret == 0);
421fb2f18f8Sesaxe
422fb2f18f8Sesaxe return (g);
423fb2f18f8Sesaxe }
424fb2f18f8Sesaxe
425fb2f18f8Sesaxe /*
426fb2f18f8Sesaxe * Find the hwset associated with the given hardware sharing type
427fb2f18f8Sesaxe */
428fb2f18f8Sesaxe group_t *
pghw_set_lookup(pghw_type_t hw)429fb2f18f8Sesaxe pghw_set_lookup(pghw_type_t hw)
430fb2f18f8Sesaxe {
431fb2f18f8Sesaxe group_t *hwset;
432fb2f18f8Sesaxe
433fb2f18f8Sesaxe if (pg_hw == NULL)
434fb2f18f8Sesaxe return (NULL);
435fb2f18f8Sesaxe
436fb2f18f8Sesaxe hwset = GROUP_ACCESS(pg_hw, (uint_t)hw);
437fb2f18f8Sesaxe return (hwset);
438fb2f18f8Sesaxe }
439fb2f18f8Sesaxe
440fb2f18f8Sesaxe /*
441fb2f18f8Sesaxe * Add a PG to a hwset
442fb2f18f8Sesaxe */
443fb2f18f8Sesaxe static void
pghw_set_add(group_t * hwset,pghw_t * pg)444fb2f18f8Sesaxe pghw_set_add(group_t *hwset, pghw_t *pg)
445fb2f18f8Sesaxe {
446fb2f18f8Sesaxe (void) group_add(hwset, pg, GRP_RESIZE);
447fb2f18f8Sesaxe }
448fb2f18f8Sesaxe
449fb2f18f8Sesaxe /*
450fb2f18f8Sesaxe * Remove a PG from a hwset
451fb2f18f8Sesaxe */
452fb2f18f8Sesaxe static void
pghw_set_remove(group_t * hwset,pghw_t * pg)453fb2f18f8Sesaxe pghw_set_remove(group_t *hwset, pghw_t *pg)
454fb2f18f8Sesaxe {
455fb2f18f8Sesaxe int result;
456fb2f18f8Sesaxe
457fb2f18f8Sesaxe result = group_remove(hwset, pg, GRP_RESIZE);
458fb2f18f8Sesaxe ASSERT(result == 0);
459fb2f18f8Sesaxe }
460fb2f18f8Sesaxe
461fb2f18f8Sesaxe /*
462fb2f18f8Sesaxe * Return a string name given a pg_hw sharing type
463fb2f18f8Sesaxe */
464b885580bSAlexander Kolbasov char *
pghw_type_string(pghw_type_t hw)465fb2f18f8Sesaxe pghw_type_string(pghw_type_t hw)
466fb2f18f8Sesaxe {
467fb2f18f8Sesaxe switch (hw) {
468fb2f18f8Sesaxe case PGHW_IPIPE:
4690e751525SEric Saxe return ("Integer Pipeline");
470fb2f18f8Sesaxe case PGHW_CACHE:
4710e751525SEric Saxe return ("Cache");
472fb2f18f8Sesaxe case PGHW_FPU:
4730e751525SEric Saxe return ("Floating Point Unit");
474e853d8c3Sjc25722 case PGHW_MPIPE:
4750e751525SEric Saxe return ("Data Pipe to memory");
476fb2f18f8Sesaxe case PGHW_CHIP:
4770e751525SEric Saxe return ("Socket");
478fb2f18f8Sesaxe case PGHW_MEMORY:
4790e751525SEric Saxe return ("Memory");
4800e751525SEric Saxe case PGHW_POW_ACTIVE:
4810e751525SEric Saxe return ("CPU PM Active Power Domain");
4820e751525SEric Saxe case PGHW_POW_IDLE:
4830e751525SEric Saxe return ("CPU PM Idle Power Domain");
484fb2f18f8Sesaxe default:
485fb2f18f8Sesaxe return ("unknown");
486fb2f18f8Sesaxe }
487fb2f18f8Sesaxe }
488fb2f18f8Sesaxe
489fb2f18f8Sesaxe /*
490fb2f18f8Sesaxe * Create / Update routines for PG hw kstats
491fb2f18f8Sesaxe *
492fb2f18f8Sesaxe * It is the intention of these kstats to provide some level
493fb2f18f8Sesaxe * of informational / debugging observability into the types
494fb2f18f8Sesaxe * and nature of the system's detected hardware sharing relationships
495fb2f18f8Sesaxe */
496fb2f18f8Sesaxe void
pghw_kstat_create(pghw_t * pg)497fb2f18f8Sesaxe pghw_kstat_create(pghw_t *pg)
498fb2f18f8Sesaxe {
499*d3c97224SAlexander Kolbasov char *sharing = pghw_type_string(pg->pghw_hw);
500*d3c97224SAlexander Kolbasov char name[KSTAT_STRLEN + 1];
501b885580bSAlexander Kolbasov
502fb2f18f8Sesaxe /*
503*d3c97224SAlexander Kolbasov * Canonify PG name to conform to kstat name rules
504*d3c97224SAlexander Kolbasov */
505*d3c97224SAlexander Kolbasov (void) strncpy(name, pghw_type_string(pg->pghw_hw), KSTAT_STRLEN + 1);
506*d3c97224SAlexander Kolbasov strident_canon(name, KSTAT_STRLEN + 1);
507*d3c97224SAlexander Kolbasov
508*d3c97224SAlexander Kolbasov /*
509*d3c97224SAlexander Kolbasov * Create a hardware performance kstat
510fb2f18f8Sesaxe */
511fb2f18f8Sesaxe if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id,
512b885580bSAlexander Kolbasov "pg", "pg",
513b885580bSAlexander Kolbasov KSTAT_TYPE_NAMED,
514fb2f18f8Sesaxe sizeof (pghw_kstat) / sizeof (kstat_named_t),
515fb2f18f8Sesaxe KSTAT_FLAG_VIRTUAL)) != NULL) {
5160e751525SEric Saxe /* Class string, hw string, and policy string */
517fb2f18f8Sesaxe pg->pghw_kstat->ks_data_size += PG_CLASS_NAME_MAX;
5180e751525SEric Saxe pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
5190e751525SEric Saxe pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
520fb2f18f8Sesaxe pg->pghw_kstat->ks_lock = &pghw_kstat_lock;
521fb2f18f8Sesaxe pg->pghw_kstat->ks_data = &pghw_kstat;
522fb2f18f8Sesaxe pg->pghw_kstat->ks_update = pghw_kstat_update;
523fb2f18f8Sesaxe pg->pghw_kstat->ks_private = pg;
524fb2f18f8Sesaxe kstat_install(pg->pghw_kstat);
525fb2f18f8Sesaxe }
526b885580bSAlexander Kolbasov
527b885580bSAlexander Kolbasov if (pg_cpulist_maxlen == 0)
528b885580bSAlexander Kolbasov pg_cpulist_maxlen = CPUSTR_LEN(max_ncpus);
529b885580bSAlexander Kolbasov
530b885580bSAlexander Kolbasov /*
531b885580bSAlexander Kolbasov * Create a physical pg kstat
532b885580bSAlexander Kolbasov */
533*d3c97224SAlexander Kolbasov if ((pg->pghw_cu_kstat = kstat_create("pg_hw_perf", ((pg_t *)pg)->pg_id,
534*d3c97224SAlexander Kolbasov name, "processor_group",
535b885580bSAlexander Kolbasov KSTAT_TYPE_NAMED,
536b885580bSAlexander Kolbasov sizeof (pghw_cu_kstat) / sizeof (kstat_named_t),
537b885580bSAlexander Kolbasov KSTAT_FLAG_VIRTUAL)) != NULL) {
538b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_lock = &pghw_kstat_lock;
539b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_data = &pghw_cu_kstat;
540b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_update = pghw_cu_kstat_update;
541b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_private = pg;
542*d3c97224SAlexander Kolbasov pg->pghw_cu_kstat->ks_data_size += strlen(sharing) + 1;
543b885580bSAlexander Kolbasov /* Allow space for CPU strings */
544b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
545b885580bSAlexander Kolbasov pg->pghw_cu_kstat->ks_data_size += pg_cpulist_maxlen;
546b885580bSAlexander Kolbasov kstat_install(pg->pghw_cu_kstat);
547b885580bSAlexander Kolbasov }
548fb2f18f8Sesaxe }
549fb2f18f8Sesaxe
550fb2f18f8Sesaxe int
pghw_kstat_update(kstat_t * ksp,int rw)551fb2f18f8Sesaxe pghw_kstat_update(kstat_t *ksp, int rw)
552fb2f18f8Sesaxe {
553fb2f18f8Sesaxe struct pghw_kstat *pgsp = &pghw_kstat;
554fb2f18f8Sesaxe pghw_t *pg = ksp->ks_private;
555fb2f18f8Sesaxe
556fb2f18f8Sesaxe if (rw == KSTAT_WRITE)
557fb2f18f8Sesaxe return (EACCES);
558fb2f18f8Sesaxe
559b885580bSAlexander Kolbasov pgsp->pg_id.value.ui32 = ((pg_t *)pg)->pg_id;
560b885580bSAlexander Kolbasov pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
561b885580bSAlexander Kolbasov pgsp->pg_instance_id.value.ui32 = pg->pghw_instance;
562fb2f18f8Sesaxe kstat_named_setstr(&pgsp->pg_class, ((pg_t *)pg)->pg_class->pgc_name);
563fb2f18f8Sesaxe kstat_named_setstr(&pgsp->pg_hw, pghw_type_string(pg->pghw_hw));
5640e751525SEric Saxe kstat_named_setstr(&pgsp->pg_policy, pg_policy_name((pg_t *)pg));
565fb2f18f8Sesaxe return (0);
566fb2f18f8Sesaxe }
567b885580bSAlexander Kolbasov
568b885580bSAlexander Kolbasov int
pghw_cu_kstat_update(kstat_t * ksp,int rw)569b885580bSAlexander Kolbasov pghw_cu_kstat_update(kstat_t *ksp, int rw)
570b885580bSAlexander Kolbasov {
571b885580bSAlexander Kolbasov struct pghw_cu_kstat *pgsp = &pghw_cu_kstat;
572b885580bSAlexander Kolbasov pghw_t *pg = ksp->ks_private;
573b885580bSAlexander Kolbasov pghw_util_t *hw_util = &pg->pghw_stats;
574*d3c97224SAlexander Kolbasov boolean_t has_cpc_privilege;
575b885580bSAlexander Kolbasov
576b885580bSAlexander Kolbasov if (rw == KSTAT_WRITE)
577b885580bSAlexander Kolbasov return (EACCES);
578b885580bSAlexander Kolbasov
579*d3c97224SAlexander Kolbasov /*
580*d3c97224SAlexander Kolbasov * Check whether the caller has priv_cpc_cpu privilege. If he doesn't,
581*d3c97224SAlexander Kolbasov * he will not get hardware utilization data.
582*d3c97224SAlexander Kolbasov */
583*d3c97224SAlexander Kolbasov
584*d3c97224SAlexander Kolbasov has_cpc_privilege = (secpolicy_cpc_cpu(crgetcred()) == 0);
585*d3c97224SAlexander Kolbasov
586*d3c97224SAlexander Kolbasov pgsp->pg_id.value.i32 = ((pg_t *)pg)->pg_id;
587*d3c97224SAlexander Kolbasov pgsp->pg_parent_id.value.i32 = (int)pghw_parent_id(pg);
588*d3c97224SAlexander Kolbasov
589b885580bSAlexander Kolbasov pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
590b885580bSAlexander Kolbasov
591b885580bSAlexander Kolbasov /*
592b885580bSAlexander Kolbasov * Allocate memory for the string representing the list of CPUs in PG.
593b885580bSAlexander Kolbasov * This memory should persist past the call to pghw_cu_kstat_update()
594b885580bSAlexander Kolbasov * since the kstat snapshot routine will reference this memory.
595b885580bSAlexander Kolbasov */
596b885580bSAlexander Kolbasov pghw_cpulist_alloc(pg);
597b885580bSAlexander Kolbasov
598b885580bSAlexander Kolbasov if (pg->pghw_kstat_gen != pg->pghw_generation) {
599b885580bSAlexander Kolbasov /*
600b885580bSAlexander Kolbasov * PG kstat generation number is out of sync with PG's
601b885580bSAlexander Kolbasov * generation mumber. It means that some CPUs could have joined
602b885580bSAlexander Kolbasov * or left PG and it is not possible to compare the numbers
603b885580bSAlexander Kolbasov * obtained before and after the generation change.
604b885580bSAlexander Kolbasov *
605b885580bSAlexander Kolbasov * Reset the maximum utilization rate and start computing it
606b885580bSAlexander Kolbasov * from scratch.
607b885580bSAlexander Kolbasov */
608b885580bSAlexander Kolbasov hw_util->pghw_util = 0;
609b885580bSAlexander Kolbasov hw_util->pghw_rate_max = 0;
610b885580bSAlexander Kolbasov pg->pghw_kstat_gen = pg->pghw_generation;
611b885580bSAlexander Kolbasov }
612b885580bSAlexander Kolbasov
613b885580bSAlexander Kolbasov /*
614b885580bSAlexander Kolbasov * We can't block on CPU lock because when PG is destroyed (under
615b885580bSAlexander Kolbasov * cpu_lock) it tries to delete this kstat and it will wait for us to
616b885580bSAlexander Kolbasov * complete which will never happen since we are waiting for cpu_lock to
617b885580bSAlexander Kolbasov * drop. Deadlocks are fun!
618b885580bSAlexander Kolbasov */
619b885580bSAlexander Kolbasov if (mutex_tryenter(&cpu_lock)) {
620b885580bSAlexander Kolbasov if (pg->pghw_cpulist != NULL &&
621b885580bSAlexander Kolbasov *(pg->pghw_cpulist) == '\0') {
622b885580bSAlexander Kolbasov (void) group2intlist(&(((pg_t *)pg)->pg_cpus),
623b885580bSAlexander Kolbasov pg->pghw_cpulist, pg->pghw_cpulist_len, cpu2id);
624b885580bSAlexander Kolbasov }
625*d3c97224SAlexander Kolbasov
626*d3c97224SAlexander Kolbasov if (has_cpc_privilege)
627b885580bSAlexander Kolbasov cu_pg_update(pg);
628*d3c97224SAlexander Kolbasov
629b885580bSAlexander Kolbasov mutex_exit(&cpu_lock);
630b885580bSAlexander Kolbasov }
631b885580bSAlexander Kolbasov
632b885580bSAlexander Kolbasov pgsp->pg_generation.value.ui32 = pg->pghw_kstat_gen;
633b885580bSAlexander Kolbasov if (pg->pghw_cpulist != NULL)
634b885580bSAlexander Kolbasov kstat_named_setstr(&pgsp->pg_cpus, pg->pghw_cpulist);
635b885580bSAlexander Kolbasov else
636b885580bSAlexander Kolbasov kstat_named_setstr(&pgsp->pg_cpus, "");
637b885580bSAlexander Kolbasov
638*d3c97224SAlexander Kolbasov kstat_named_setstr(&pgsp->pg_relationship,
639*d3c97224SAlexander Kolbasov pghw_type_string(pg->pghw_hw));
640*d3c97224SAlexander Kolbasov
641*d3c97224SAlexander Kolbasov if (has_cpc_privilege) {
642*d3c97224SAlexander Kolbasov pgsp->pg_hw_util.value.ui64 = hw_util->pghw_util;
643*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_time_running.value.ui64 =
644*d3c97224SAlexander Kolbasov hw_util->pghw_time_running;
645*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_time_stopped.value.ui64 =
646*d3c97224SAlexander Kolbasov hw_util->pghw_time_stopped;
647*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_rate.value.ui64 = hw_util->pghw_rate;
648*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_rate_max.value.ui64 = hw_util->pghw_rate_max;
649*d3c97224SAlexander Kolbasov } else {
650*d3c97224SAlexander Kolbasov pgsp->pg_hw_util.value.ui64 = 0;
651*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_time_running.value.ui64 = 0;
652*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_time_stopped.value.ui64 = 0;
653*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_rate.value.ui64 = 0;
654*d3c97224SAlexander Kolbasov pgsp->pg_hw_util_rate_max.value.ui64 = 0;
655*d3c97224SAlexander Kolbasov }
656b885580bSAlexander Kolbasov
657b885580bSAlexander Kolbasov return (0);
658b885580bSAlexander Kolbasov }
659b885580bSAlexander Kolbasov
660b885580bSAlexander Kolbasov /*
661b885580bSAlexander Kolbasov * Update the string representation of CPUs in PG (pg->pghw_cpulist).
662b885580bSAlexander Kolbasov * The string representation is used for kstats.
663b885580bSAlexander Kolbasov *
664b885580bSAlexander Kolbasov * The string is allocated if it has not already been or if it is already
665b885580bSAlexander Kolbasov * allocated and PG has more CPUs now. If PG has smaller or equal number of
666b885580bSAlexander Kolbasov * CPUs, but the actual CPUs may have changed, the string is reset to the empty
667b885580bSAlexander Kolbasov * string causes the string representation to be recreated. The pghw_generation
668b885580bSAlexander Kolbasov * field is used to detect whether CPUs within the pg may have changed.
669b885580bSAlexander Kolbasov */
670b885580bSAlexander Kolbasov static void
pghw_cpulist_alloc(pghw_t * pg)671b885580bSAlexander Kolbasov pghw_cpulist_alloc(pghw_t *pg)
672b885580bSAlexander Kolbasov {
673b885580bSAlexander Kolbasov uint_t ncpus = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
674b885580bSAlexander Kolbasov size_t len = CPUSTR_LEN(ncpus);
675b885580bSAlexander Kolbasov
676b885580bSAlexander Kolbasov /*
677b885580bSAlexander Kolbasov * If the pghw_cpulist string is already allocated we need to make sure
678b885580bSAlexander Kolbasov * that it has sufficient length. Also if the set of CPUs may have
679b885580bSAlexander Kolbasov * changed, we need to re-generate the string.
680b885580bSAlexander Kolbasov */
681b885580bSAlexander Kolbasov if (pg->pghw_cpulist != NULL &&
682b885580bSAlexander Kolbasov pg->pghw_kstat_gen != pg->pghw_generation) {
683b885580bSAlexander Kolbasov if (len <= pg->pghw_cpulist_len) {
684b885580bSAlexander Kolbasov /*
685b885580bSAlexander Kolbasov * There is sufficient space in the pghw_cpulist for
686b885580bSAlexander Kolbasov * the new set of CPUs. Just clear the string to trigger
687b885580bSAlexander Kolbasov * re-generation of list of CPUs
688b885580bSAlexander Kolbasov */
689b885580bSAlexander Kolbasov *(pg->pghw_cpulist) = '\0';
690b885580bSAlexander Kolbasov } else {
691b885580bSAlexander Kolbasov /*
692b885580bSAlexander Kolbasov * There is, potentially, insufficient space in
693b885580bSAlexander Kolbasov * pghw_cpulist, so reallocate the string.
694b885580bSAlexander Kolbasov */
695b885580bSAlexander Kolbasov ASSERT(strlen(pg->pghw_cpulist) < pg->pghw_cpulist_len);
696b885580bSAlexander Kolbasov kmem_free(pg->pghw_cpulist, pg->pghw_cpulist_len);
697b885580bSAlexander Kolbasov pg->pghw_cpulist = NULL;
698b885580bSAlexander Kolbasov pg->pghw_cpulist_len = 0;
699b885580bSAlexander Kolbasov }
700b885580bSAlexander Kolbasov }
701b885580bSAlexander Kolbasov
702b885580bSAlexander Kolbasov if (pg->pghw_cpulist == NULL) {
703b885580bSAlexander Kolbasov /*
704b885580bSAlexander Kolbasov * Allocate space to hold cpulist.
705b885580bSAlexander Kolbasov *
706b885580bSAlexander Kolbasov * Length can not be bigger that the maximum space we have
707b885580bSAlexander Kolbasov * allowed for the kstat buffer
708b885580bSAlexander Kolbasov */
709b885580bSAlexander Kolbasov if (len > pg_cpulist_maxlen)
710b885580bSAlexander Kolbasov len = pg_cpulist_maxlen;
711b885580bSAlexander Kolbasov if (len > 0) {
712b885580bSAlexander Kolbasov pg->pghw_cpulist = kmem_zalloc(len, KM_NOSLEEP);
713b885580bSAlexander Kolbasov if (pg->pghw_cpulist != NULL)
714b885580bSAlexander Kolbasov pg->pghw_cpulist_len = len;
715b885580bSAlexander Kolbasov }
716b885580bSAlexander Kolbasov }
717b885580bSAlexander Kolbasov }
718b885580bSAlexander Kolbasov
719b885580bSAlexander Kolbasov static int
cpu2id(void * v)720b885580bSAlexander Kolbasov cpu2id(void *v)
721b885580bSAlexander Kolbasov {
722b885580bSAlexander Kolbasov cpu_t *cp = (cpu_t *)v;
723b885580bSAlexander Kolbasov
724b885580bSAlexander Kolbasov ASSERT(v != NULL);
725b885580bSAlexander Kolbasov
726b885580bSAlexander Kolbasov return (cp->cpu_id);
727b885580bSAlexander Kolbasov }
728*d3c97224SAlexander Kolbasov
729*d3c97224SAlexander Kolbasov /*
730*d3c97224SAlexander Kolbasov * Return parent ID or -1 if there is no parent.
731*d3c97224SAlexander Kolbasov * All hardware PGs are currently also CMT PGs, but for safety we check the
732*d3c97224SAlexander Kolbasov * class matches cmt before we upcast the pghw pointer to pg_cmt_t.
733*d3c97224SAlexander Kolbasov */
734*d3c97224SAlexander Kolbasov static pgid_t
pghw_parent_id(pghw_t * pghw)735*d3c97224SAlexander Kolbasov pghw_parent_id(pghw_t *pghw)
736*d3c97224SAlexander Kolbasov {
737*d3c97224SAlexander Kolbasov pg_t *pg = (pg_t *)pghw;
738*d3c97224SAlexander Kolbasov pgid_t parent_id = -1;
739*d3c97224SAlexander Kolbasov
740*d3c97224SAlexander Kolbasov if (pg != NULL && strcmp(pg->pg_class->pgc_name, "cmt") == 0) {
741*d3c97224SAlexander Kolbasov pg_cmt_t *cmt = (pg_cmt_t *)pg;
742*d3c97224SAlexander Kolbasov pg_t *parent = (pg_t *)cmt->cmt_parent;
743*d3c97224SAlexander Kolbasov if (parent != NULL)
744*d3c97224SAlexander Kolbasov parent_id = parent->pg_id;
745*d3c97224SAlexander Kolbasov }
746*d3c97224SAlexander Kolbasov
747*d3c97224SAlexander Kolbasov return (parent_id);
748*d3c97224SAlexander Kolbasov }
749