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