13434Sesaxe /*
23434Sesaxe * CDDL HEADER START
33434Sesaxe *
43434Sesaxe * The contents of this file are subject to the terms of the
53434Sesaxe * Common Development and Distribution License (the "License").
63434Sesaxe * You may not use this file except in compliance with the License.
73434Sesaxe *
83434Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93434Sesaxe * or http://www.opensolaris.org/os/licensing.
103434Sesaxe * See the License for the specific language governing permissions
113434Sesaxe * and limitations under the License.
123434Sesaxe *
133434Sesaxe * When distributing Covered Code, include this CDDL HEADER in each
143434Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153434Sesaxe * If applicable, add the following below this CDDL HEADER, with the
163434Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying
173434Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner]
183434Sesaxe *
193434Sesaxe * CDDL HEADER END
203434Sesaxe */
213434Sesaxe /*
22*13124SAlexander.Kolbasov@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
233434Sesaxe */
243434Sesaxe
253434Sesaxe #include <sys/systm.h>
263434Sesaxe #include <sys/types.h>
273434Sesaxe #include <sys/param.h>
283434Sesaxe #include <sys/thread.h>
293434Sesaxe #include <sys/cpuvar.h>
303434Sesaxe #include <sys/kmem.h>
313434Sesaxe #include <sys/cmn_err.h>
32*13124SAlexander.Kolbasov@Sun.COM #include <sys/policy.h>
333434Sesaxe #include <sys/group.h>
343434Sesaxe #include <sys/pg.h>
353434Sesaxe #include <sys/pghw.h>
368906SEric.Saxe@Sun.COM #include <sys/cpu_pm.h>
3711389SAlexander.Kolbasov@Sun.COM #include <sys/cap_util.h>
383434Sesaxe
393434Sesaxe /*
403434Sesaxe * Processor Groups: Hardware sharing relationship layer
413434Sesaxe *
423434Sesaxe * This file implements an extension to Processor Groups to capture
433434Sesaxe * hardware sharing relationships existing between logical CPUs. Examples of
443434Sesaxe * hardware sharing relationships include shared caches on some CMT
453434Sesaxe * procesoor architectures, or shared local memory controllers on NUMA
463434Sesaxe * based system architectures.
473434Sesaxe *
483434Sesaxe * The pghw_t structure represents the extended PG. The first member
493434Sesaxe * of the structure is the generic pg_t with the pghw specific members
503434Sesaxe * following. The generic pg_t *must* remain the first member of the
513434Sesaxe * structure as the code uses casting of structure references to access
523434Sesaxe * the generic pg_t structure elements.
533434Sesaxe *
543434Sesaxe * In addition to the generic CPU grouping, physical PGs have a hardware
553434Sesaxe * sharing relationship enumerated "type", and an instance id. The enumerated
563434Sesaxe * type is defined by the pghw_type_t enumeration, while the instance id
573434Sesaxe * uniquely identifies the sharing instance from among others of the same
583434Sesaxe * hardware sharing type.
593434Sesaxe *
603434Sesaxe * The physical PGs are organized into an overall hierarchy, and are tracked
613434Sesaxe * in a number of different per CPU, and per pghw_type_t type groups.
623434Sesaxe * As an example:
633434Sesaxe *
643434Sesaxe * -------------
653434Sesaxe * | pg_hw |
663434Sesaxe * | (group_t) |
673434Sesaxe * -------------
683434Sesaxe * || ============================
693434Sesaxe * ||\\-----------------------// \\ \\
703434Sesaxe * || | hwset (PGC_HW_CHIP) | ------------- -------------
713434Sesaxe * || | (group_t) | | pghw_t | | pghw_t |
723434Sesaxe * || ----------------------- | chip 0 | | chip 1 |
733434Sesaxe * || ------------- -------------
743434Sesaxe * || \\ \\ \\ \\ \\ \\ \\ \\
753434Sesaxe * || cpu cpu cpu cpu cpu cpu cpu cpu
763434Sesaxe * ||
773434Sesaxe * || ============================
783434Sesaxe * ||\\-----------------------// \\ \\
793434Sesaxe * || | hwset (PGC_HW_IPIPE)| ------------- -------------
803434Sesaxe * || | (group_t) | | pghw_t | | pghw_t |
813434Sesaxe * || ----------------------- | ipipe 0 | | ipipe 1 |
823434Sesaxe * || ------------- -------------
833434Sesaxe * || \\ \\ \\ \\
843434Sesaxe * || cpu cpu cpu cpu
853434Sesaxe * ...
863434Sesaxe *
873434Sesaxe *
883434Sesaxe * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group
893434Sesaxe * of physical PGs of the same hardware sharing type. Within each hwset, the
903434Sesaxe * PG's instance id uniquely identifies the grouping relationshsip among other
913434Sesaxe * groupings of the same sharing type. The instance id for a grouping is
923434Sesaxe * platform defined, and in some cases may be used by platform code as a handle
933434Sesaxe * to search for a particular relationship instance.
943434Sesaxe *
953434Sesaxe * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs
963434Sesaxe * that participate in the sharing relationship. Each CPU also has associated
973434Sesaxe * with it a grouping tracking the PGs in which the CPU belongs. This can be
983434Sesaxe * used to iterate over the various relationships in which the CPU participates
993434Sesaxe * (the CPU's chip, cache, lgroup, etc.).
1003434Sesaxe *
1013434Sesaxe * The hwsets are created dynamically as new hardware sharing relationship types
1028906SEric.Saxe@Sun.COM * are instantiated. They are never destroyed, as once a given relationship
1033434Sesaxe * type appears in the system, it is quite likely that at least one instance of
1043434Sesaxe * that relationship will always persist as long as the system is running.
1053434Sesaxe */
1063434Sesaxe
1073434Sesaxe static group_t *pg_hw; /* top level pg hw group */
1083434Sesaxe
1093434Sesaxe /*
1103434Sesaxe * Physical PG kstats
1113434Sesaxe */
1123434Sesaxe struct pghw_kstat {
1133434Sesaxe kstat_named_t pg_id;
1143434Sesaxe kstat_named_t pg_class;
1153434Sesaxe kstat_named_t pg_ncpus;
1163434Sesaxe kstat_named_t pg_instance_id;
1173434Sesaxe kstat_named_t pg_hw;
1188906SEric.Saxe@Sun.COM kstat_named_t pg_policy;
1193434Sesaxe } pghw_kstat = {
120*13124SAlexander.Kolbasov@Sun.COM { "id", KSTAT_DATA_INT32 },
1213434Sesaxe { "pg_class", KSTAT_DATA_STRING },
12211389SAlexander.Kolbasov@Sun.COM { "ncpus", KSTAT_DATA_UINT32 },
12311389SAlexander.Kolbasov@Sun.COM { "instance_id", KSTAT_DATA_UINT32 },
1243434Sesaxe { "hardware", KSTAT_DATA_STRING },
1258906SEric.Saxe@Sun.COM { "policy", KSTAT_DATA_STRING },
1263434Sesaxe };
1273434Sesaxe
1283434Sesaxe kmutex_t pghw_kstat_lock;
1293434Sesaxe
1303434Sesaxe /*
13111389SAlexander.Kolbasov@Sun.COM * Capacity and Utilization PG kstats
13211389SAlexander.Kolbasov@Sun.COM *
13311389SAlexander.Kolbasov@Sun.COM * These kstats are updated one at a time, so we can have a single scratch space
13411389SAlexander.Kolbasov@Sun.COM * to fill the data.
13511389SAlexander.Kolbasov@Sun.COM *
13611389SAlexander.Kolbasov@Sun.COM * kstat fields:
13711389SAlexander.Kolbasov@Sun.COM *
138*13124SAlexander.Kolbasov@Sun.COM * pg_id PG ID for PG described by this kstat
139*13124SAlexander.Kolbasov@Sun.COM *
140*13124SAlexander.Kolbasov@Sun.COM * pg_parent Parent PG ID. The value -1 means "no parent".
14111389SAlexander.Kolbasov@Sun.COM *
14211389SAlexander.Kolbasov@Sun.COM * pg_ncpus Number of CPUs within this PG
14311389SAlexander.Kolbasov@Sun.COM *
14411389SAlexander.Kolbasov@Sun.COM * pg_cpus String describing CPUs within this PG
14511389SAlexander.Kolbasov@Sun.COM *
146*13124SAlexander.Kolbasov@Sun.COM * pg_relationship Name of sharing relationship for this PG
14711389SAlexander.Kolbasov@Sun.COM *
14811389SAlexander.Kolbasov@Sun.COM * pg_generation Generation value that increases whenever any CPU leaves
14911389SAlexander.Kolbasov@Sun.COM * or joins PG. Two kstat snapshots for the same
15011389SAlexander.Kolbasov@Sun.COM * CPU may only be compared if they have the same
15111389SAlexander.Kolbasov@Sun.COM * generation
15211389SAlexander.Kolbasov@Sun.COM *
15311389SAlexander.Kolbasov@Sun.COM * pg_hw_util Running value of PG utilization for the sharing
15411389SAlexander.Kolbasov@Sun.COM * relationship
15511389SAlexander.Kolbasov@Sun.COM *
15611389SAlexander.Kolbasov@Sun.COM * pg_hw_util_time_running
15711389SAlexander.Kolbasov@Sun.COM * Total time spent collecting CU data. The time may be
15811389SAlexander.Kolbasov@Sun.COM * less than wall time if CU counters were stopped for
15911389SAlexander.Kolbasov@Sun.COM * some time.
16011389SAlexander.Kolbasov@Sun.COM *
16111389SAlexander.Kolbasov@Sun.COM * pg_hw_util_time_stopped Total time the CU counters were stopped.
16211389SAlexander.Kolbasov@Sun.COM *
16311389SAlexander.Kolbasov@Sun.COM * pg_hw_util_rate Utilization rate, expressed in operations per second.
16411389SAlexander.Kolbasov@Sun.COM *
16511389SAlexander.Kolbasov@Sun.COM * pg_hw_util_rate_max Maximum observed value of utilization rate.
16611389SAlexander.Kolbasov@Sun.COM */
16711389SAlexander.Kolbasov@Sun.COM struct pghw_cu_kstat {
16811389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_id;
169*13124SAlexander.Kolbasov@Sun.COM kstat_named_t pg_parent_id;
17011389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_ncpus;
17111389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_generation;
17211389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_hw_util;
17311389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_hw_util_time_running;
17411389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_hw_util_time_stopped;
17511389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_hw_util_rate;
17611389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_hw_util_rate_max;
17711389SAlexander.Kolbasov@Sun.COM kstat_named_t pg_cpus;
178*13124SAlexander.Kolbasov@Sun.COM kstat_named_t pg_relationship;
17911389SAlexander.Kolbasov@Sun.COM } pghw_cu_kstat = {
180*13124SAlexander.Kolbasov@Sun.COM { "pg_id", KSTAT_DATA_INT32 },
181*13124SAlexander.Kolbasov@Sun.COM { "parent_pg_id", KSTAT_DATA_INT32 },
18211389SAlexander.Kolbasov@Sun.COM { "ncpus", KSTAT_DATA_UINT32 },
18311389SAlexander.Kolbasov@Sun.COM { "generation", KSTAT_DATA_UINT32 },
18411389SAlexander.Kolbasov@Sun.COM { "hw_util", KSTAT_DATA_UINT64 },
18511389SAlexander.Kolbasov@Sun.COM { "hw_util_time_running", KSTAT_DATA_UINT64 },
18611389SAlexander.Kolbasov@Sun.COM { "hw_util_time_stopped", KSTAT_DATA_UINT64 },
18711389SAlexander.Kolbasov@Sun.COM { "hw_util_rate", KSTAT_DATA_UINT64 },
18811389SAlexander.Kolbasov@Sun.COM { "hw_util_rate_max", KSTAT_DATA_UINT64 },
18911389SAlexander.Kolbasov@Sun.COM { "cpus", KSTAT_DATA_STRING },
190*13124SAlexander.Kolbasov@Sun.COM { "relationship", KSTAT_DATA_STRING },
19111389SAlexander.Kolbasov@Sun.COM };
19211389SAlexander.Kolbasov@Sun.COM
19311389SAlexander.Kolbasov@Sun.COM /*
19411389SAlexander.Kolbasov@Sun.COM * Calculate the string size to represent NCPUS. Allow 5 digits for each CPU ID
19511389SAlexander.Kolbasov@Sun.COM * plus one space per CPU plus NUL byte in the end. This is only an estimate,
19611389SAlexander.Kolbasov@Sun.COM * since we try to compress CPU ranges as x-y. In the worst case the string
19711389SAlexander.Kolbasov@Sun.COM * representation of CPUs may be truncated.
19811389SAlexander.Kolbasov@Sun.COM */
19911389SAlexander.Kolbasov@Sun.COM #define CPUSTR_LEN(ncpus) ((ncpus) * 6)
20011389SAlexander.Kolbasov@Sun.COM
20111389SAlexander.Kolbasov@Sun.COM /*
20211389SAlexander.Kolbasov@Sun.COM * Maximum length of the string that represents list of CPUs
20311389SAlexander.Kolbasov@Sun.COM */
20411389SAlexander.Kolbasov@Sun.COM static int pg_cpulist_maxlen = 0;
20511389SAlexander.Kolbasov@Sun.COM
20611389SAlexander.Kolbasov@Sun.COM static void pghw_kstat_create(pghw_t *);
20711389SAlexander.Kolbasov@Sun.COM static int pghw_kstat_update(kstat_t *, int);
20811389SAlexander.Kolbasov@Sun.COM static int pghw_cu_kstat_update(kstat_t *, int);
20911389SAlexander.Kolbasov@Sun.COM static int cpu2id(void *);
21011389SAlexander.Kolbasov@Sun.COM
21111389SAlexander.Kolbasov@Sun.COM /*
2123434Sesaxe * hwset operations
2133434Sesaxe */
2143434Sesaxe static group_t *pghw_set_create(pghw_type_t);
2153434Sesaxe static void pghw_set_add(group_t *, pghw_t *);
2163434Sesaxe static void pghw_set_remove(group_t *, pghw_t *);
2173434Sesaxe
21811389SAlexander.Kolbasov@Sun.COM static void pghw_cpulist_alloc(pghw_t *);
21911389SAlexander.Kolbasov@Sun.COM static int cpu2id(void *);
220*13124SAlexander.Kolbasov@Sun.COM static pgid_t pghw_parent_id(pghw_t *);
22111389SAlexander.Kolbasov@Sun.COM
2223434Sesaxe /*
2238906SEric.Saxe@Sun.COM * Initialize the physical portion of a hardware PG
2243434Sesaxe */
2253434Sesaxe void
pghw_init(pghw_t * pg,cpu_t * cp,pghw_type_t hw)2263434Sesaxe pghw_init(pghw_t *pg, cpu_t *cp, pghw_type_t hw)
2273434Sesaxe {
2283434Sesaxe group_t *hwset;
2293434Sesaxe
2303434Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) {
2313434Sesaxe /*
2323434Sesaxe * Haven't seen this hardware type yet
2333434Sesaxe */
2343434Sesaxe hwset = pghw_set_create(hw);
2353434Sesaxe }
2363434Sesaxe
2373434Sesaxe pghw_set_add(hwset, pg);
2383434Sesaxe pg->pghw_hw = hw;
23911389SAlexander.Kolbasov@Sun.COM pg->pghw_generation = 0;
2403434Sesaxe pg->pghw_instance =
2413434Sesaxe pg_plat_hw_instance_id(cp, hw);
2423434Sesaxe pghw_kstat_create(pg);
2438906SEric.Saxe@Sun.COM
2448906SEric.Saxe@Sun.COM /*
2458906SEric.Saxe@Sun.COM * Hardware sharing relationship specific initialization
2468906SEric.Saxe@Sun.COM */
2478906SEric.Saxe@Sun.COM switch (pg->pghw_hw) {
2488906SEric.Saxe@Sun.COM case PGHW_POW_ACTIVE:
2498906SEric.Saxe@Sun.COM pg->pghw_handle =
2508906SEric.Saxe@Sun.COM (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_ACTIVE);
2518906SEric.Saxe@Sun.COM break;
2528906SEric.Saxe@Sun.COM case PGHW_POW_IDLE:
2538906SEric.Saxe@Sun.COM pg->pghw_handle =
2548906SEric.Saxe@Sun.COM (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_IDLE);
2558906SEric.Saxe@Sun.COM break;
2568906SEric.Saxe@Sun.COM default:
2578906SEric.Saxe@Sun.COM pg->pghw_handle = (pghw_handle_t)NULL;
2588906SEric.Saxe@Sun.COM }
2593434Sesaxe }
2603434Sesaxe
2613434Sesaxe /*
2623434Sesaxe * Teardown the physical portion of a physical PG
2633434Sesaxe */
2643434Sesaxe void
pghw_fini(pghw_t * pg)2653434Sesaxe pghw_fini(pghw_t *pg)
2663434Sesaxe {
2673434Sesaxe group_t *hwset;
2683434Sesaxe
269*13124SAlexander.Kolbasov@Sun.COM pghw_cmt_fini(pg);
270*13124SAlexander.Kolbasov@Sun.COM
2713434Sesaxe hwset = pghw_set_lookup(pg->pghw_hw);
2723434Sesaxe ASSERT(hwset != NULL);
2733434Sesaxe
2743434Sesaxe pghw_set_remove(hwset, pg);
2753434Sesaxe pg->pghw_instance = (id_t)PGHW_INSTANCE_ANON;
2763434Sesaxe pg->pghw_hw = (pghw_type_t)-1;
2773434Sesaxe
27811389SAlexander.Kolbasov@Sun.COM if (pg->pghw_kstat != NULL)
2793434Sesaxe kstat_delete(pg->pghw_kstat);
28011389SAlexander.Kolbasov@Sun.COM
281*13124SAlexander.Kolbasov@Sun.COM }
282*13124SAlexander.Kolbasov@Sun.COM
283*13124SAlexander.Kolbasov@Sun.COM /*
284*13124SAlexander.Kolbasov@Sun.COM * PG is removed from CMT hierarchy
285*13124SAlexander.Kolbasov@Sun.COM */
286*13124SAlexander.Kolbasov@Sun.COM void
pghw_cmt_fini(pghw_t * pg)287*13124SAlexander.Kolbasov@Sun.COM pghw_cmt_fini(pghw_t *pg)
288*13124SAlexander.Kolbasov@Sun.COM {
28911389SAlexander.Kolbasov@Sun.COM /*
29011389SAlexander.Kolbasov@Sun.COM * Destroy string representation of CPUs
29111389SAlexander.Kolbasov@Sun.COM */
29211389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist != NULL) {
29311389SAlexander.Kolbasov@Sun.COM kmem_free(pg->pghw_cpulist,
29411389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist_len);
29511389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist = NULL;
29611389SAlexander.Kolbasov@Sun.COM }
29711389SAlexander.Kolbasov@Sun.COM
298*13124SAlexander.Kolbasov@Sun.COM /*
299*13124SAlexander.Kolbasov@Sun.COM * Destroy CU kstats
300*13124SAlexander.Kolbasov@Sun.COM */
301*13124SAlexander.Kolbasov@Sun.COM if (pg->pghw_cu_kstat != NULL) {
30211389SAlexander.Kolbasov@Sun.COM kstat_delete(pg->pghw_cu_kstat);
303*13124SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat = NULL;
304*13124SAlexander.Kolbasov@Sun.COM }
3053434Sesaxe }
3063434Sesaxe
3073434Sesaxe /*
3083434Sesaxe * Find an existing physical PG in which to place
3093434Sesaxe * the given CPU for the specified hardware sharing
3103434Sesaxe * relationship
3113434Sesaxe */
3123434Sesaxe pghw_t *
pghw_place_cpu(cpu_t * cp,pghw_type_t hw)3133434Sesaxe pghw_place_cpu(cpu_t *cp, pghw_type_t hw)
3143434Sesaxe {
3153434Sesaxe group_t *hwset;
3163434Sesaxe
3173434Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) {
3183434Sesaxe return (NULL);
3193434Sesaxe }
3203434Sesaxe
3213434Sesaxe return ((pghw_t *)pg_cpu_find_pg(cp, hwset));
3223434Sesaxe }
3233434Sesaxe
3243434Sesaxe /*
3253434Sesaxe * Find the pg representing the hw sharing relationship in which
3263434Sesaxe * cp belongs
3273434Sesaxe */
3283434Sesaxe pghw_t *
pghw_find_pg(cpu_t * cp,pghw_type_t hw)3293434Sesaxe pghw_find_pg(cpu_t *cp, pghw_type_t hw)
3303434Sesaxe {
3313434Sesaxe group_iter_t i;
3323434Sesaxe pghw_t *pg;
3333434Sesaxe
3343434Sesaxe group_iter_init(&i);
3353434Sesaxe while ((pg = group_iterate(&cp->cpu_pg->pgs, &i)) != NULL) {
3363434Sesaxe if (pg->pghw_hw == hw)
3373434Sesaxe return (pg);
3383434Sesaxe }
3393434Sesaxe return (NULL);
3403434Sesaxe }
3413434Sesaxe
3423434Sesaxe /*
3433434Sesaxe * Find the PG of the given hardware sharing relationship
3443434Sesaxe * type with the given instance id
3453434Sesaxe */
3463434Sesaxe pghw_t *
pghw_find_by_instance(id_t id,pghw_type_t hw)3473434Sesaxe pghw_find_by_instance(id_t id, pghw_type_t hw)
3483434Sesaxe {
3493434Sesaxe group_iter_t i;
3503434Sesaxe group_t *set;
3513434Sesaxe pghw_t *pg;
3523434Sesaxe
3533434Sesaxe set = pghw_set_lookup(hw);
3543434Sesaxe if (!set)
3553434Sesaxe return (NULL);
3563434Sesaxe
3573434Sesaxe group_iter_init(&i);
3583434Sesaxe while ((pg = group_iterate(set, &i)) != NULL) {
3593434Sesaxe if (pg->pghw_instance == id)
3603434Sesaxe return (pg);
3613434Sesaxe }
3623434Sesaxe return (NULL);
3633434Sesaxe }
3643434Sesaxe
3653434Sesaxe /*
3663434Sesaxe * CPUs physical ID cache creation / destruction
3673434Sesaxe * The cache's elements are initialized to the CPU's id
3683434Sesaxe */
3693434Sesaxe void
pghw_physid_create(cpu_t * cp)3703434Sesaxe pghw_physid_create(cpu_t *cp)
3713434Sesaxe {
3723434Sesaxe int i;
3733434Sesaxe
3743434Sesaxe cp->cpu_physid = kmem_alloc(sizeof (cpu_physid_t), KM_SLEEP);
3753434Sesaxe
3763434Sesaxe for (i = 0; i < (sizeof (cpu_physid_t) / sizeof (id_t)); i++) {
3773434Sesaxe ((id_t *)cp->cpu_physid)[i] = cp->cpu_id;
3783434Sesaxe }
3793434Sesaxe }
3803434Sesaxe
3813434Sesaxe void
pghw_physid_destroy(cpu_t * cp)3823434Sesaxe pghw_physid_destroy(cpu_t *cp)
3833434Sesaxe {
3843434Sesaxe if (cp->cpu_physid) {
3853434Sesaxe kmem_free(cp->cpu_physid, sizeof (cpu_physid_t));
3863434Sesaxe cp->cpu_physid = NULL;
3873434Sesaxe }
3883434Sesaxe }
3893434Sesaxe
3903434Sesaxe /*
3913434Sesaxe * Create a new, empty hwset.
3923434Sesaxe * This routine may block, and must not be called from any
3933434Sesaxe * paused CPU context.
3943434Sesaxe */
3953434Sesaxe static group_t *
pghw_set_create(pghw_type_t hw)3963434Sesaxe pghw_set_create(pghw_type_t hw)
3973434Sesaxe {
3983434Sesaxe group_t *g;
3993434Sesaxe int ret;
4003434Sesaxe
4013434Sesaxe /*
4023434Sesaxe * Create the top level PG hw group if it doesn't already exist
4033434Sesaxe * This is a "set" of hardware sets, that is ordered (and indexed)
4043434Sesaxe * by the pghw_type_t enum.
4053434Sesaxe */
4063434Sesaxe if (pg_hw == NULL) {
4073434Sesaxe pg_hw = kmem_alloc(sizeof (group_t), KM_SLEEP);
4083434Sesaxe group_create(pg_hw);
4093434Sesaxe group_expand(pg_hw, (uint_t)PGHW_NUM_COMPONENTS);
4103434Sesaxe }
4113434Sesaxe
4123434Sesaxe /*
4133434Sesaxe * Create the new hwset
4143434Sesaxe * Add it to the top level pg_hw group.
4153434Sesaxe */
4163434Sesaxe g = kmem_alloc(sizeof (group_t), KM_SLEEP);
4173434Sesaxe group_create(g);
4183434Sesaxe
4193434Sesaxe ret = group_add_at(pg_hw, g, (uint_t)hw);
4203434Sesaxe ASSERT(ret == 0);
4213434Sesaxe
4223434Sesaxe return (g);
4233434Sesaxe }
4243434Sesaxe
4253434Sesaxe /*
4263434Sesaxe * Find the hwset associated with the given hardware sharing type
4273434Sesaxe */
4283434Sesaxe group_t *
pghw_set_lookup(pghw_type_t hw)4293434Sesaxe pghw_set_lookup(pghw_type_t hw)
4303434Sesaxe {
4313434Sesaxe group_t *hwset;
4323434Sesaxe
4333434Sesaxe if (pg_hw == NULL)
4343434Sesaxe return (NULL);
4353434Sesaxe
4363434Sesaxe hwset = GROUP_ACCESS(pg_hw, (uint_t)hw);
4373434Sesaxe return (hwset);
4383434Sesaxe }
4393434Sesaxe
4403434Sesaxe /*
4413434Sesaxe * Add a PG to a hwset
4423434Sesaxe */
4433434Sesaxe static void
pghw_set_add(group_t * hwset,pghw_t * pg)4443434Sesaxe pghw_set_add(group_t *hwset, pghw_t *pg)
4453434Sesaxe {
4463434Sesaxe (void) group_add(hwset, pg, GRP_RESIZE);
4473434Sesaxe }
4483434Sesaxe
4493434Sesaxe /*
4503434Sesaxe * Remove a PG from a hwset
4513434Sesaxe */
4523434Sesaxe static void
pghw_set_remove(group_t * hwset,pghw_t * pg)4533434Sesaxe pghw_set_remove(group_t *hwset, pghw_t *pg)
4543434Sesaxe {
4553434Sesaxe int result;
4563434Sesaxe
4573434Sesaxe result = group_remove(hwset, pg, GRP_RESIZE);
4583434Sesaxe ASSERT(result == 0);
4593434Sesaxe }
4603434Sesaxe
4613434Sesaxe /*
4623434Sesaxe * Return a string name given a pg_hw sharing type
4633434Sesaxe */
46411389SAlexander.Kolbasov@Sun.COM char *
pghw_type_string(pghw_type_t hw)4653434Sesaxe pghw_type_string(pghw_type_t hw)
4663434Sesaxe {
4673434Sesaxe switch (hw) {
4683434Sesaxe case PGHW_IPIPE:
4698906SEric.Saxe@Sun.COM return ("Integer Pipeline");
4703434Sesaxe case PGHW_CACHE:
4718906SEric.Saxe@Sun.COM return ("Cache");
4723434Sesaxe case PGHW_FPU:
4738906SEric.Saxe@Sun.COM return ("Floating Point Unit");
4745079Sjc25722 case PGHW_MPIPE:
4758906SEric.Saxe@Sun.COM return ("Data Pipe to memory");
4763434Sesaxe case PGHW_CHIP:
4778906SEric.Saxe@Sun.COM return ("Socket");
4783434Sesaxe case PGHW_MEMORY:
4798906SEric.Saxe@Sun.COM return ("Memory");
4808906SEric.Saxe@Sun.COM case PGHW_POW_ACTIVE:
4818906SEric.Saxe@Sun.COM return ("CPU PM Active Power Domain");
4828906SEric.Saxe@Sun.COM case PGHW_POW_IDLE:
4838906SEric.Saxe@Sun.COM return ("CPU PM Idle Power Domain");
4843434Sesaxe default:
4853434Sesaxe return ("unknown");
4863434Sesaxe }
4873434Sesaxe }
4883434Sesaxe
4893434Sesaxe /*
4903434Sesaxe * Create / Update routines for PG hw kstats
4913434Sesaxe *
4923434Sesaxe * It is the intention of these kstats to provide some level
4933434Sesaxe * of informational / debugging observability into the types
4943434Sesaxe * and nature of the system's detected hardware sharing relationships
4953434Sesaxe */
4963434Sesaxe void
pghw_kstat_create(pghw_t * pg)4973434Sesaxe pghw_kstat_create(pghw_t *pg)
4983434Sesaxe {
499*13124SAlexander.Kolbasov@Sun.COM char *sharing = pghw_type_string(pg->pghw_hw);
500*13124SAlexander.Kolbasov@Sun.COM char name[KSTAT_STRLEN + 1];
50111389SAlexander.Kolbasov@Sun.COM
5023434Sesaxe /*
503*13124SAlexander.Kolbasov@Sun.COM * Canonify PG name to conform to kstat name rules
504*13124SAlexander.Kolbasov@Sun.COM */
505*13124SAlexander.Kolbasov@Sun.COM (void) strncpy(name, pghw_type_string(pg->pghw_hw), KSTAT_STRLEN + 1);
506*13124SAlexander.Kolbasov@Sun.COM strident_canon(name, KSTAT_STRLEN + 1);
507*13124SAlexander.Kolbasov@Sun.COM
508*13124SAlexander.Kolbasov@Sun.COM /*
509*13124SAlexander.Kolbasov@Sun.COM * Create a hardware performance kstat
5103434Sesaxe */
5113434Sesaxe if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id,
51211389SAlexander.Kolbasov@Sun.COM "pg", "pg",
51311389SAlexander.Kolbasov@Sun.COM KSTAT_TYPE_NAMED,
5143434Sesaxe sizeof (pghw_kstat) / sizeof (kstat_named_t),
5153434Sesaxe KSTAT_FLAG_VIRTUAL)) != NULL) {
5168906SEric.Saxe@Sun.COM /* Class string, hw string, and policy string */
5173434Sesaxe pg->pghw_kstat->ks_data_size += PG_CLASS_NAME_MAX;
5188906SEric.Saxe@Sun.COM pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
5198906SEric.Saxe@Sun.COM pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
5203434Sesaxe pg->pghw_kstat->ks_lock = &pghw_kstat_lock;
5213434Sesaxe pg->pghw_kstat->ks_data = &pghw_kstat;
5223434Sesaxe pg->pghw_kstat->ks_update = pghw_kstat_update;
5233434Sesaxe pg->pghw_kstat->ks_private = pg;
5243434Sesaxe kstat_install(pg->pghw_kstat);
5253434Sesaxe }
52611389SAlexander.Kolbasov@Sun.COM
52711389SAlexander.Kolbasov@Sun.COM if (pg_cpulist_maxlen == 0)
52811389SAlexander.Kolbasov@Sun.COM pg_cpulist_maxlen = CPUSTR_LEN(max_ncpus);
52911389SAlexander.Kolbasov@Sun.COM
53011389SAlexander.Kolbasov@Sun.COM /*
53111389SAlexander.Kolbasov@Sun.COM * Create a physical pg kstat
53211389SAlexander.Kolbasov@Sun.COM */
533*13124SAlexander.Kolbasov@Sun.COM if ((pg->pghw_cu_kstat = kstat_create("pg_hw_perf", ((pg_t *)pg)->pg_id,
534*13124SAlexander.Kolbasov@Sun.COM name, "processor_group",
53511389SAlexander.Kolbasov@Sun.COM KSTAT_TYPE_NAMED,
53611389SAlexander.Kolbasov@Sun.COM sizeof (pghw_cu_kstat) / sizeof (kstat_named_t),
53711389SAlexander.Kolbasov@Sun.COM KSTAT_FLAG_VIRTUAL)) != NULL) {
53811389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_lock = &pghw_kstat_lock;
53911389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_data = &pghw_cu_kstat;
54011389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_update = pghw_cu_kstat_update;
54111389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_private = pg;
542*13124SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_data_size += strlen(sharing) + 1;
54311389SAlexander.Kolbasov@Sun.COM /* Allow space for CPU strings */
54411389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
54511389SAlexander.Kolbasov@Sun.COM pg->pghw_cu_kstat->ks_data_size += pg_cpulist_maxlen;
54611389SAlexander.Kolbasov@Sun.COM kstat_install(pg->pghw_cu_kstat);
54711389SAlexander.Kolbasov@Sun.COM }
5483434Sesaxe }
5493434Sesaxe
5503434Sesaxe int
pghw_kstat_update(kstat_t * ksp,int rw)5513434Sesaxe pghw_kstat_update(kstat_t *ksp, int rw)
5523434Sesaxe {
5533434Sesaxe struct pghw_kstat *pgsp = &pghw_kstat;
5543434Sesaxe pghw_t *pg = ksp->ks_private;
5553434Sesaxe
5563434Sesaxe if (rw == KSTAT_WRITE)
5573434Sesaxe return (EACCES);
5583434Sesaxe
55911389SAlexander.Kolbasov@Sun.COM pgsp->pg_id.value.ui32 = ((pg_t *)pg)->pg_id;
56011389SAlexander.Kolbasov@Sun.COM pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
56111389SAlexander.Kolbasov@Sun.COM pgsp->pg_instance_id.value.ui32 = pg->pghw_instance;
5623434Sesaxe kstat_named_setstr(&pgsp->pg_class, ((pg_t *)pg)->pg_class->pgc_name);
5633434Sesaxe kstat_named_setstr(&pgsp->pg_hw, pghw_type_string(pg->pghw_hw));
5648906SEric.Saxe@Sun.COM kstat_named_setstr(&pgsp->pg_policy, pg_policy_name((pg_t *)pg));
5653434Sesaxe return (0);
5663434Sesaxe }
56711389SAlexander.Kolbasov@Sun.COM
56811389SAlexander.Kolbasov@Sun.COM int
pghw_cu_kstat_update(kstat_t * ksp,int rw)56911389SAlexander.Kolbasov@Sun.COM pghw_cu_kstat_update(kstat_t *ksp, int rw)
57011389SAlexander.Kolbasov@Sun.COM {
57111389SAlexander.Kolbasov@Sun.COM struct pghw_cu_kstat *pgsp = &pghw_cu_kstat;
57211389SAlexander.Kolbasov@Sun.COM pghw_t *pg = ksp->ks_private;
57311389SAlexander.Kolbasov@Sun.COM pghw_util_t *hw_util = &pg->pghw_stats;
574*13124SAlexander.Kolbasov@Sun.COM boolean_t has_cpc_privilege;
57511389SAlexander.Kolbasov@Sun.COM
57611389SAlexander.Kolbasov@Sun.COM if (rw == KSTAT_WRITE)
57711389SAlexander.Kolbasov@Sun.COM return (EACCES);
57811389SAlexander.Kolbasov@Sun.COM
579*13124SAlexander.Kolbasov@Sun.COM /*
580*13124SAlexander.Kolbasov@Sun.COM * Check whether the caller has priv_cpc_cpu privilege. If he doesn't,
581*13124SAlexander.Kolbasov@Sun.COM * he will not get hardware utilization data.
582*13124SAlexander.Kolbasov@Sun.COM */
583*13124SAlexander.Kolbasov@Sun.COM
584*13124SAlexander.Kolbasov@Sun.COM has_cpc_privilege = (secpolicy_cpc_cpu(crgetcred()) == 0);
585*13124SAlexander.Kolbasov@Sun.COM
586*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_id.value.i32 = ((pg_t *)pg)->pg_id;
587*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_parent_id.value.i32 = (int)pghw_parent_id(pg);
588*13124SAlexander.Kolbasov@Sun.COM
58911389SAlexander.Kolbasov@Sun.COM pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
59011389SAlexander.Kolbasov@Sun.COM
59111389SAlexander.Kolbasov@Sun.COM /*
59211389SAlexander.Kolbasov@Sun.COM * Allocate memory for the string representing the list of CPUs in PG.
59311389SAlexander.Kolbasov@Sun.COM * This memory should persist past the call to pghw_cu_kstat_update()
59411389SAlexander.Kolbasov@Sun.COM * since the kstat snapshot routine will reference this memory.
59511389SAlexander.Kolbasov@Sun.COM */
59611389SAlexander.Kolbasov@Sun.COM pghw_cpulist_alloc(pg);
59711389SAlexander.Kolbasov@Sun.COM
59811389SAlexander.Kolbasov@Sun.COM if (pg->pghw_kstat_gen != pg->pghw_generation) {
59911389SAlexander.Kolbasov@Sun.COM /*
60011389SAlexander.Kolbasov@Sun.COM * PG kstat generation number is out of sync with PG's
60111389SAlexander.Kolbasov@Sun.COM * generation mumber. It means that some CPUs could have joined
60211389SAlexander.Kolbasov@Sun.COM * or left PG and it is not possible to compare the numbers
60311389SAlexander.Kolbasov@Sun.COM * obtained before and after the generation change.
60411389SAlexander.Kolbasov@Sun.COM *
60511389SAlexander.Kolbasov@Sun.COM * Reset the maximum utilization rate and start computing it
60611389SAlexander.Kolbasov@Sun.COM * from scratch.
60711389SAlexander.Kolbasov@Sun.COM */
60811389SAlexander.Kolbasov@Sun.COM hw_util->pghw_util = 0;
60911389SAlexander.Kolbasov@Sun.COM hw_util->pghw_rate_max = 0;
61011389SAlexander.Kolbasov@Sun.COM pg->pghw_kstat_gen = pg->pghw_generation;
61111389SAlexander.Kolbasov@Sun.COM }
61211389SAlexander.Kolbasov@Sun.COM
61311389SAlexander.Kolbasov@Sun.COM /*
61411389SAlexander.Kolbasov@Sun.COM * We can't block on CPU lock because when PG is destroyed (under
61511389SAlexander.Kolbasov@Sun.COM * cpu_lock) it tries to delete this kstat and it will wait for us to
61611389SAlexander.Kolbasov@Sun.COM * complete which will never happen since we are waiting for cpu_lock to
61711389SAlexander.Kolbasov@Sun.COM * drop. Deadlocks are fun!
61811389SAlexander.Kolbasov@Sun.COM */
61911389SAlexander.Kolbasov@Sun.COM if (mutex_tryenter(&cpu_lock)) {
62011389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist != NULL &&
62111389SAlexander.Kolbasov@Sun.COM *(pg->pghw_cpulist) == '\0') {
62211389SAlexander.Kolbasov@Sun.COM (void) group2intlist(&(((pg_t *)pg)->pg_cpus),
62311389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist, pg->pghw_cpulist_len, cpu2id);
62411389SAlexander.Kolbasov@Sun.COM }
625*13124SAlexander.Kolbasov@Sun.COM
626*13124SAlexander.Kolbasov@Sun.COM if (has_cpc_privilege)
627*13124SAlexander.Kolbasov@Sun.COM cu_pg_update(pg);
628*13124SAlexander.Kolbasov@Sun.COM
62911389SAlexander.Kolbasov@Sun.COM mutex_exit(&cpu_lock);
63011389SAlexander.Kolbasov@Sun.COM }
63111389SAlexander.Kolbasov@Sun.COM
63211389SAlexander.Kolbasov@Sun.COM pgsp->pg_generation.value.ui32 = pg->pghw_kstat_gen;
63311389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist != NULL)
63411389SAlexander.Kolbasov@Sun.COM kstat_named_setstr(&pgsp->pg_cpus, pg->pghw_cpulist);
63511389SAlexander.Kolbasov@Sun.COM else
63611389SAlexander.Kolbasov@Sun.COM kstat_named_setstr(&pgsp->pg_cpus, "");
63711389SAlexander.Kolbasov@Sun.COM
638*13124SAlexander.Kolbasov@Sun.COM kstat_named_setstr(&pgsp->pg_relationship,
639*13124SAlexander.Kolbasov@Sun.COM pghw_type_string(pg->pghw_hw));
640*13124SAlexander.Kolbasov@Sun.COM
641*13124SAlexander.Kolbasov@Sun.COM if (has_cpc_privilege) {
642*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util.value.ui64 = hw_util->pghw_util;
643*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_time_running.value.ui64 =
644*13124SAlexander.Kolbasov@Sun.COM hw_util->pghw_time_running;
645*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_time_stopped.value.ui64 =
646*13124SAlexander.Kolbasov@Sun.COM hw_util->pghw_time_stopped;
647*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_rate.value.ui64 = hw_util->pghw_rate;
648*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_rate_max.value.ui64 = hw_util->pghw_rate_max;
649*13124SAlexander.Kolbasov@Sun.COM } else {
650*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util.value.ui64 = 0;
651*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_time_running.value.ui64 = 0;
652*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_time_stopped.value.ui64 = 0;
653*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_rate.value.ui64 = 0;
654*13124SAlexander.Kolbasov@Sun.COM pgsp->pg_hw_util_rate_max.value.ui64 = 0;
655*13124SAlexander.Kolbasov@Sun.COM }
65611389SAlexander.Kolbasov@Sun.COM
65711389SAlexander.Kolbasov@Sun.COM return (0);
65811389SAlexander.Kolbasov@Sun.COM }
65911389SAlexander.Kolbasov@Sun.COM
66011389SAlexander.Kolbasov@Sun.COM /*
66111389SAlexander.Kolbasov@Sun.COM * Update the string representation of CPUs in PG (pg->pghw_cpulist).
66211389SAlexander.Kolbasov@Sun.COM * The string representation is used for kstats.
66311389SAlexander.Kolbasov@Sun.COM *
66411389SAlexander.Kolbasov@Sun.COM * The string is allocated if it has not already been or if it is already
66511389SAlexander.Kolbasov@Sun.COM * allocated and PG has more CPUs now. If PG has smaller or equal number of
66611389SAlexander.Kolbasov@Sun.COM * CPUs, but the actual CPUs may have changed, the string is reset to the empty
66711389SAlexander.Kolbasov@Sun.COM * string causes the string representation to be recreated. The pghw_generation
66811389SAlexander.Kolbasov@Sun.COM * field is used to detect whether CPUs within the pg may have changed.
66911389SAlexander.Kolbasov@Sun.COM */
67011389SAlexander.Kolbasov@Sun.COM static void
pghw_cpulist_alloc(pghw_t * pg)67111389SAlexander.Kolbasov@Sun.COM pghw_cpulist_alloc(pghw_t *pg)
67211389SAlexander.Kolbasov@Sun.COM {
67311389SAlexander.Kolbasov@Sun.COM uint_t ncpus = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
67411389SAlexander.Kolbasov@Sun.COM size_t len = CPUSTR_LEN(ncpus);
67511389SAlexander.Kolbasov@Sun.COM
67611389SAlexander.Kolbasov@Sun.COM /*
67711389SAlexander.Kolbasov@Sun.COM * If the pghw_cpulist string is already allocated we need to make sure
67811389SAlexander.Kolbasov@Sun.COM * that it has sufficient length. Also if the set of CPUs may have
67911389SAlexander.Kolbasov@Sun.COM * changed, we need to re-generate the string.
68011389SAlexander.Kolbasov@Sun.COM */
68111389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist != NULL &&
68211389SAlexander.Kolbasov@Sun.COM pg->pghw_kstat_gen != pg->pghw_generation) {
68311389SAlexander.Kolbasov@Sun.COM if (len <= pg->pghw_cpulist_len) {
68411389SAlexander.Kolbasov@Sun.COM /*
68511389SAlexander.Kolbasov@Sun.COM * There is sufficient space in the pghw_cpulist for
68611389SAlexander.Kolbasov@Sun.COM * the new set of CPUs. Just clear the string to trigger
68711389SAlexander.Kolbasov@Sun.COM * re-generation of list of CPUs
68811389SAlexander.Kolbasov@Sun.COM */
68911389SAlexander.Kolbasov@Sun.COM *(pg->pghw_cpulist) = '\0';
69011389SAlexander.Kolbasov@Sun.COM } else {
69111389SAlexander.Kolbasov@Sun.COM /*
69211389SAlexander.Kolbasov@Sun.COM * There is, potentially, insufficient space in
69311389SAlexander.Kolbasov@Sun.COM * pghw_cpulist, so reallocate the string.
69411389SAlexander.Kolbasov@Sun.COM */
69511389SAlexander.Kolbasov@Sun.COM ASSERT(strlen(pg->pghw_cpulist) < pg->pghw_cpulist_len);
69611389SAlexander.Kolbasov@Sun.COM kmem_free(pg->pghw_cpulist, pg->pghw_cpulist_len);
69711389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist = NULL;
69811389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist_len = 0;
69911389SAlexander.Kolbasov@Sun.COM }
70011389SAlexander.Kolbasov@Sun.COM }
70111389SAlexander.Kolbasov@Sun.COM
70211389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist == NULL) {
70311389SAlexander.Kolbasov@Sun.COM /*
70411389SAlexander.Kolbasov@Sun.COM * Allocate space to hold cpulist.
70511389SAlexander.Kolbasov@Sun.COM *
70611389SAlexander.Kolbasov@Sun.COM * Length can not be bigger that the maximum space we have
70711389SAlexander.Kolbasov@Sun.COM * allowed for the kstat buffer
70811389SAlexander.Kolbasov@Sun.COM */
70911389SAlexander.Kolbasov@Sun.COM if (len > pg_cpulist_maxlen)
71011389SAlexander.Kolbasov@Sun.COM len = pg_cpulist_maxlen;
71111389SAlexander.Kolbasov@Sun.COM if (len > 0) {
71211389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist = kmem_zalloc(len, KM_NOSLEEP);
71311389SAlexander.Kolbasov@Sun.COM if (pg->pghw_cpulist != NULL)
71411389SAlexander.Kolbasov@Sun.COM pg->pghw_cpulist_len = len;
71511389SAlexander.Kolbasov@Sun.COM }
71611389SAlexander.Kolbasov@Sun.COM }
71711389SAlexander.Kolbasov@Sun.COM }
71811389SAlexander.Kolbasov@Sun.COM
71911389SAlexander.Kolbasov@Sun.COM static int
cpu2id(void * v)72011389SAlexander.Kolbasov@Sun.COM cpu2id(void *v)
72111389SAlexander.Kolbasov@Sun.COM {
72211389SAlexander.Kolbasov@Sun.COM cpu_t *cp = (cpu_t *)v;
72311389SAlexander.Kolbasov@Sun.COM
72411389SAlexander.Kolbasov@Sun.COM ASSERT(v != NULL);
72511389SAlexander.Kolbasov@Sun.COM
72611389SAlexander.Kolbasov@Sun.COM return (cp->cpu_id);
72711389SAlexander.Kolbasov@Sun.COM }
728*13124SAlexander.Kolbasov@Sun.COM
729*13124SAlexander.Kolbasov@Sun.COM /*
730*13124SAlexander.Kolbasov@Sun.COM * Return parent ID or -1 if there is no parent.
731*13124SAlexander.Kolbasov@Sun.COM * All hardware PGs are currently also CMT PGs, but for safety we check the
732*13124SAlexander.Kolbasov@Sun.COM * class matches cmt before we upcast the pghw pointer to pg_cmt_t.
733*13124SAlexander.Kolbasov@Sun.COM */
734*13124SAlexander.Kolbasov@Sun.COM static pgid_t
pghw_parent_id(pghw_t * pghw)735*13124SAlexander.Kolbasov@Sun.COM pghw_parent_id(pghw_t *pghw)
736*13124SAlexander.Kolbasov@Sun.COM {
737*13124SAlexander.Kolbasov@Sun.COM pg_t *pg = (pg_t *)pghw;
738*13124SAlexander.Kolbasov@Sun.COM pgid_t parent_id = -1;
739*13124SAlexander.Kolbasov@Sun.COM
740*13124SAlexander.Kolbasov@Sun.COM if (pg != NULL && strcmp(pg->pg_class->pgc_name, "cmt") == 0) {
741*13124SAlexander.Kolbasov@Sun.COM pg_cmt_t *cmt = (pg_cmt_t *)pg;
742*13124SAlexander.Kolbasov@Sun.COM pg_t *parent = (pg_t *)cmt->cmt_parent;
743*13124SAlexander.Kolbasov@Sun.COM if (parent != NULL)
744*13124SAlexander.Kolbasov@Sun.COM parent_id = parent->pg_id;
745*13124SAlexander.Kolbasov@Sun.COM }
746*13124SAlexander.Kolbasov@Sun.COM
747*13124SAlexander.Kolbasov@Sun.COM return (parent_id);
748*13124SAlexander.Kolbasov@Sun.COM }
749