10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*2685Sakolb * Common Development and Distribution License (the "License").
6*2685Sakolb * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*2685Sakolb
220Sstevel@tonic-gate /*
23*2685Sakolb * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include "lgrp.h"
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
320Sstevel@tonic-gate #include <sys/cpuvar.h>
330Sstevel@tonic-gate #include <sys/lgrp.h>
340Sstevel@tonic-gate #include <sys/cpupart.h>
350Sstevel@tonic-gate
360Sstevel@tonic-gate int
print_range(int start,int end,int separator)370Sstevel@tonic-gate print_range(int start, int end, int separator)
380Sstevel@tonic-gate {
390Sstevel@tonic-gate int count;
400Sstevel@tonic-gate char tmp;
410Sstevel@tonic-gate char *format;
420Sstevel@tonic-gate
430Sstevel@tonic-gate if (start == end) {
440Sstevel@tonic-gate /* Unfortunately, mdb_printf returns void */
450Sstevel@tonic-gate format = separator ? ", %d" : "%d";
460Sstevel@tonic-gate mdb_printf(format, start);
470Sstevel@tonic-gate count = mdb_snprintf(&tmp, 1, format, start);
480Sstevel@tonic-gate } else {
490Sstevel@tonic-gate format = separator ? ", %d-%d" : "%d-%d";
500Sstevel@tonic-gate mdb_printf(format, start, end);
510Sstevel@tonic-gate count = mdb_snprintf(&tmp, 1, format, start, end);
520Sstevel@tonic-gate }
530Sstevel@tonic-gate
540Sstevel@tonic-gate return (count);
550Sstevel@tonic-gate }
560Sstevel@tonic-gate
570Sstevel@tonic-gate void
print_cpuset_range(ulong_t * cs,int words,int width)580Sstevel@tonic-gate print_cpuset_range(ulong_t *cs, int words, int width)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate int i, j;
610Sstevel@tonic-gate ulong_t m;
620Sstevel@tonic-gate int in = 0;
630Sstevel@tonic-gate int start;
640Sstevel@tonic-gate int end;
650Sstevel@tonic-gate int count = 0;
660Sstevel@tonic-gate int sep = 0;
670Sstevel@tonic-gate
680Sstevel@tonic-gate for (i = 0; i < words; i++)
690Sstevel@tonic-gate for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1)
700Sstevel@tonic-gate if (cs[i] & m) {
710Sstevel@tonic-gate if (in == 0) {
720Sstevel@tonic-gate start = i * BT_NBIPUL + j;
730Sstevel@tonic-gate in = 1;
740Sstevel@tonic-gate }
750Sstevel@tonic-gate } else {
760Sstevel@tonic-gate if (in == 1) {
770Sstevel@tonic-gate end = i * BT_NBIPUL + j - 1;
780Sstevel@tonic-gate count += print_range(start, end, sep);
790Sstevel@tonic-gate sep = 1;
800Sstevel@tonic-gate in = 0;
810Sstevel@tonic-gate }
820Sstevel@tonic-gate }
830Sstevel@tonic-gate if (in == 1) {
840Sstevel@tonic-gate end = i * BT_NBIPUL - 1;
850Sstevel@tonic-gate count += print_range(start, end, sep);
860Sstevel@tonic-gate }
870Sstevel@tonic-gate
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate * print width - count spaces
900Sstevel@tonic-gate */
910Sstevel@tonic-gate
920Sstevel@tonic-gate if (width > count)
930Sstevel@tonic-gate mdb_printf("%*s", width - count, "");
940Sstevel@tonic-gate }
950Sstevel@tonic-gate typedef struct lgrp_cpu_walk {
960Sstevel@tonic-gate uintptr_t lcw_firstcpu;
970Sstevel@tonic-gate int lcw_cpusleft;
980Sstevel@tonic-gate } lgrp_cpu_walk_t;
990Sstevel@tonic-gate
1000Sstevel@tonic-gate int
lgrp_cpulist_walk_init(mdb_walk_state_t * wsp)1010Sstevel@tonic-gate lgrp_cpulist_walk_init(mdb_walk_state_t *wsp)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate lgrp_cpu_walk_t *lcw;
1040Sstevel@tonic-gate lgrp_t lgrp;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate lcw = mdb_alloc(sizeof (lgrp_cpu_walk_t), UM_SLEEP | UM_GC);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
1090Sstevel@tonic-gate mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
1100Sstevel@tonic-gate return (WALK_ERR);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate lcw->lcw_firstcpu = (uintptr_t)lgrp.lgrp_cpu;
1140Sstevel@tonic-gate lcw->lcw_cpusleft = lgrp.lgrp_cpucnt;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate wsp->walk_data = lcw;
1170Sstevel@tonic-gate wsp->walk_addr = lcw->lcw_firstcpu;
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate return (WALK_NEXT);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate int
lgrp_cpulist_walk_step(mdb_walk_state_t * wsp)1230Sstevel@tonic-gate lgrp_cpulist_walk_step(mdb_walk_state_t *wsp)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate lgrp_cpu_walk_t *lcw = (lgrp_cpu_walk_t *)wsp->walk_data;
1260Sstevel@tonic-gate uintptr_t addr = (uintptr_t)wsp->walk_addr;
1270Sstevel@tonic-gate cpu_t cpu;
1280Sstevel@tonic-gate int status;
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate if (lcw->lcw_cpusleft-- == 0)
1310Sstevel@tonic-gate return (WALK_DONE);
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
1340Sstevel@tonic-gate mdb_warn("couldn't read 'cpu' at %p", addr);
1350Sstevel@tonic-gate return (WALK_ERR);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate status = wsp->walk_callback(addr, &cpu, wsp->walk_cbdata);
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate if (status != WALK_NEXT)
1410Sstevel@tonic-gate return (status);
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate addr = (uintptr_t)cpu.cpu_next_lgrp;
1440Sstevel@tonic-gate wsp->walk_addr = addr;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate if (lcw->lcw_cpusleft == NULL && addr != lcw->lcw_firstcpu) {
1470Sstevel@tonic-gate mdb_warn("number of cpus in lgroup cpu != lgroup cpucnt\n");
1480Sstevel@tonic-gate return (WALK_ERR);
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate return (WALK_NEXT);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate typedef struct lgrp_cpuwalk_cbdata {
1550Sstevel@tonic-gate uint_t lcc_opt_p;
1560Sstevel@tonic-gate uint_t lcc_count;
1570Sstevel@tonic-gate uint_t lcc_used;
1580Sstevel@tonic-gate uint_t *lcc_psrsetid;
1590Sstevel@tonic-gate ulong_t **lcc_cpuset;
1600Sstevel@tonic-gate uint_t *lcc_cpucnt;
1610Sstevel@tonic-gate int *lcc_loadavg;
1620Sstevel@tonic-gate } lgrp_cpuwalk_cbdata_t;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* ARGSUSED */
1650Sstevel@tonic-gate static int
lgrp_cpuwalk_callback(uintptr_t addr,const void * arg,void * cb_data)1660Sstevel@tonic-gate lgrp_cpuwalk_callback(uintptr_t addr, const void *arg, void *cb_data)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate cpu_t *cpu = (cpu_t *)arg;
1690Sstevel@tonic-gate lgrp_cpuwalk_cbdata_t *lcc = (lgrp_cpuwalk_cbdata_t *)cb_data;
1700Sstevel@tonic-gate uint_t opt_p = lcc->lcc_opt_p;
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate int offset = 0;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate * if opt_p is set, we're going to break up info for
1760Sstevel@tonic-gate * each lgrp by processor set.
1770Sstevel@tonic-gate */
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate if (opt_p != 0) {
1800Sstevel@tonic-gate cpupartid_t cp_id;
1810Sstevel@tonic-gate cpupart_t cpupart;
1820Sstevel@tonic-gate lpl_t lpl;
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate if (mdb_vread(&cpupart, sizeof (cpupart_t),
1860Sstevel@tonic-gate (uintptr_t)cpu->cpu_part) == -1) {
1870Sstevel@tonic-gate mdb_warn("cannot read cpu partition at %p",
1880Sstevel@tonic-gate cpu->cpu_part);
1890Sstevel@tonic-gate return (WALK_ERR);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate cp_id = cpupart.cp_id;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate for (offset = 0; offset < lcc->lcc_used; offset++)
1940Sstevel@tonic-gate if (cp_id == lcc->lcc_psrsetid[offset]) {
1950Sstevel@tonic-gate goto found;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate if (offset >= lcc->lcc_count) {
1990Sstevel@tonic-gate mdb_warn(
2000Sstevel@tonic-gate "number of cpu partitions changed during walk");
2010Sstevel@tonic-gate return (WALK_ERR);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate lcc->lcc_psrsetid[offset] = cp_id;
2050Sstevel@tonic-gate lcc->lcc_used++;
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if (mdb_vread(&lpl, sizeof (lpl_t), (uintptr_t)cpu->cpu_lpl)
2080Sstevel@tonic-gate == -1) {
2090Sstevel@tonic-gate mdb_warn("Cannot read lpl at %p", cpu->cpu_lpl);
2100Sstevel@tonic-gate return (WALK_ERR);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate lcc->lcc_loadavg[offset] = lpl.lpl_loadavg;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate found: lcc->lcc_cpucnt[offset]++;
2170Sstevel@tonic-gate BT_SET(lcc->lcc_cpuset[offset], cpu->cpu_id);
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate return (WALK_NEXT);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /* ARGSUSED */
2240Sstevel@tonic-gate int
lgrp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2250Sstevel@tonic-gate lgrp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate lgrp_t lgrp;
2280Sstevel@tonic-gate lgrp_cpuwalk_cbdata_t lcc;
2290Sstevel@tonic-gate int cpusetsize;
2300Sstevel@tonic-gate int lcpu; /* cpus in lgrp */
2310Sstevel@tonic-gate int _ncpu;
2320Sstevel@tonic-gate int opt_p = 0; /* display partition fraction loads */
2330Sstevel@tonic-gate int opt_q = 0; /* display only address. */
2340Sstevel@tonic-gate int i;
2350Sstevel@tonic-gate const char *s_index = NULL, *s_handle = NULL, *s_parent = NULL;
2360Sstevel@tonic-gate uintptr_t index;
2370Sstevel@tonic-gate uintptr_t handle;
2380Sstevel@tonic-gate uintptr_t parent;
2390Sstevel@tonic-gate int filters = 0;
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) {
2420Sstevel@tonic-gate if (mdb_walk_dcmd("lgrptbl", "lgrp", argc, argv) == -1) {
2430Sstevel@tonic-gate mdb_warn("can't walk 'lgrps'");
2440Sstevel@tonic-gate return (DCMD_ERR);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate return (DCMD_OK);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate if (mdb_getopts(argc, argv,
2500Sstevel@tonic-gate 'p', MDB_OPT_SETBITS, TRUE, &opt_p,
2510Sstevel@tonic-gate 'q', MDB_OPT_SETBITS, TRUE, &opt_q,
2520Sstevel@tonic-gate 'P', MDB_OPT_STR, &s_parent,
2530Sstevel@tonic-gate 'i', MDB_OPT_STR, &s_index,
2540Sstevel@tonic-gate 'h', MDB_OPT_STR, &s_handle,
2550Sstevel@tonic-gate NULL) != argc)
2560Sstevel@tonic-gate return (DCMD_USAGE);
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if (s_index != NULL)
2590Sstevel@tonic-gate filters++;
2600Sstevel@tonic-gate if (s_handle != NULL)
2610Sstevel@tonic-gate filters++;
2620Sstevel@tonic-gate if (s_parent != NULL)
2630Sstevel@tonic-gate filters++;
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate if (flags & DCMD_PIPE_OUT)
2660Sstevel@tonic-gate opt_q = B_TRUE;
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate if (s_index != NULL)
2690Sstevel@tonic-gate index = mdb_strtoull(s_index);
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate if (s_parent != NULL)
2720Sstevel@tonic-gate parent = mdb_strtoull(s_parent);
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate if (s_handle != NULL) {
2750Sstevel@tonic-gate if (strcmp(s_handle, "NULL") == 0)
2760Sstevel@tonic-gate handle = (uintptr_t)LGRP_NULL_HANDLE;
2770Sstevel@tonic-gate else if (strcmp(s_handle, "DEFAULT") == 0)
2780Sstevel@tonic-gate handle = (uintptr_t)LGRP_DEFAULT_HANDLE;
2790Sstevel@tonic-gate else
2800Sstevel@tonic-gate handle = mdb_strtoull(s_handle);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && !opt_q) {
2840Sstevel@tonic-gate if (opt_p == 0)
2850Sstevel@tonic-gate mdb_printf("%9s %?s %?s %?s %9s %9s\n",
2860Sstevel@tonic-gate "LGRPID",
2870Sstevel@tonic-gate "ADDR",
2880Sstevel@tonic-gate "PARENT",
2890Sstevel@tonic-gate "PLATHAND",
2900Sstevel@tonic-gate "#CPU",
2910Sstevel@tonic-gate "CPUS");
2920Sstevel@tonic-gate else
2930Sstevel@tonic-gate mdb_printf("%9s %9s %9s %9s %9s\n",
2940Sstevel@tonic-gate "LGRPID",
2950Sstevel@tonic-gate "PSRSETID",
2960Sstevel@tonic-gate "LOAD",
2970Sstevel@tonic-gate "#CPU",
2980Sstevel@tonic-gate "CPUS");
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate if (mdb_vread(&lgrp, sizeof (struct lgrp), addr) == -1) {
3020Sstevel@tonic-gate mdb_warn("unable to read 'lgrp' at %p", addr);
3030Sstevel@tonic-gate return (DCMD_ERR);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate /*
3070Sstevel@tonic-gate * Do not report free lgrp unless specifically asked for.
3080Sstevel@tonic-gate */
3090Sstevel@tonic-gate if ((lgrp.lgrp_id == LGRP_NONE) &&
3100Sstevel@tonic-gate ((s_index == NULL) || ((int)index != LGRP_NONE)))
3110Sstevel@tonic-gate return (DCMD_OK);
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate * If lgrp doesn't pass filtering criteria, don't print anything and
3150Sstevel@tonic-gate * just return.
3160Sstevel@tonic-gate */
3170Sstevel@tonic-gate if (filters) {
3180Sstevel@tonic-gate if ((s_parent != NULL) &&
3190Sstevel@tonic-gate parent != (uintptr_t)lgrp.lgrp_parent)
3200Sstevel@tonic-gate return (DCMD_OK);
3210Sstevel@tonic-gate if ((s_index != NULL) && index != (uintptr_t)lgrp.lgrp_id)
3220Sstevel@tonic-gate return (DCMD_OK);
3230Sstevel@tonic-gate if ((s_handle != NULL) &&
3240Sstevel@tonic-gate handle != (uintptr_t)lgrp.lgrp_plathand)
3250Sstevel@tonic-gate return (DCMD_OK);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if (opt_q) {
3290Sstevel@tonic-gate mdb_printf("%0?p\n", addr);
3300Sstevel@tonic-gate return (DCMD_OK);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * figure out what cpus we've got
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate if (mdb_readsym(&_ncpu, sizeof (int), "_ncpu") == -1) {
3380Sstevel@tonic-gate mdb_warn("symbol '_ncpu' not found");
3390Sstevel@tonic-gate return (DCMD_ERR);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate /*
3430Sstevel@tonic-gate * allocate enough space for set of longs to hold cpuid bitfield
3440Sstevel@tonic-gate */
3450Sstevel@tonic-gate if (opt_p)
3460Sstevel@tonic-gate lcpu = lgrp.lgrp_cpucnt;
3470Sstevel@tonic-gate else
3480Sstevel@tonic-gate lcpu = 1;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate cpusetsize = BT_BITOUL(_ncpu) * sizeof (uintptr_t);
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate lcc.lcc_used = 0;
3530Sstevel@tonic-gate lcc.lcc_cpucnt = mdb_zalloc(sizeof (uint_t) * lcpu,
3540Sstevel@tonic-gate UM_SLEEP | UM_GC);
3550Sstevel@tonic-gate lcc.lcc_psrsetid = mdb_zalloc(sizeof (uint_t) * lcpu,
3560Sstevel@tonic-gate UM_SLEEP | UM_GC);
3570Sstevel@tonic-gate lcc.lcc_cpuset = mdb_zalloc(sizeof (uintptr_t) * lcpu,
3580Sstevel@tonic-gate UM_SLEEP | UM_GC);
3590Sstevel@tonic-gate for (i = 0; i < lcpu; i++)
3600Sstevel@tonic-gate lcc.lcc_cpuset[i] = mdb_zalloc(cpusetsize,
3610Sstevel@tonic-gate UM_SLEEP | UM_GC);
3620Sstevel@tonic-gate lcc.lcc_loadavg = mdb_zalloc(sizeof (int) * lcpu,
3630Sstevel@tonic-gate UM_SLEEP | UM_GC);
3640Sstevel@tonic-gate lcc.lcc_count = lcpu;
3650Sstevel@tonic-gate lcc.lcc_opt_p = opt_p;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate if (mdb_pwalk("lgrp_cpulist", lgrp_cpuwalk_callback, &lcc,
3680Sstevel@tonic-gate addr) == -1) {
3690Sstevel@tonic-gate mdb_warn("unable to walk lgrp_cpulist");
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate if (opt_p == 0) {
3730Sstevel@tonic-gate if (lgrp.lgrp_plathand == LGRP_NULL_HANDLE) {
3740Sstevel@tonic-gate mdb_printf("%9d %?p %?p %?s %9d ",
3750Sstevel@tonic-gate lgrp.lgrp_id,
3760Sstevel@tonic-gate addr,
3770Sstevel@tonic-gate lgrp.lgrp_parent,
3780Sstevel@tonic-gate "NULL",
3790Sstevel@tonic-gate lgrp.lgrp_cpucnt);
3800Sstevel@tonic-gate } else if (lgrp.lgrp_plathand == LGRP_DEFAULT_HANDLE) {
3810Sstevel@tonic-gate mdb_printf("%9d %?p %?p %?s %9d ",
3820Sstevel@tonic-gate lgrp.lgrp_id,
3830Sstevel@tonic-gate addr,
3840Sstevel@tonic-gate lgrp.lgrp_parent,
3850Sstevel@tonic-gate "DEFAULT",
3860Sstevel@tonic-gate lgrp.lgrp_cpucnt);
3870Sstevel@tonic-gate } else {
3880Sstevel@tonic-gate mdb_printf("%9d %?p %?p %?p %9d ",
3890Sstevel@tonic-gate lgrp.lgrp_id,
3900Sstevel@tonic-gate addr,
3910Sstevel@tonic-gate lgrp.lgrp_parent,
3920Sstevel@tonic-gate lgrp.lgrp_plathand,
3930Sstevel@tonic-gate lgrp.lgrp_cpucnt);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate if (lgrp.lgrp_cpucnt != 0) {
3970Sstevel@tonic-gate print_cpuset_range(lcc.lcc_cpuset[0],
3980Sstevel@tonic-gate cpusetsize/sizeof (ulong_t), 0);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate mdb_printf("\n");
4010Sstevel@tonic-gate } else {
4020Sstevel@tonic-gate for (i = 0; i < lcc.lcc_used; i++) {
4030Sstevel@tonic-gate mdb_printf("%9d %9d %9d %9d ",
4040Sstevel@tonic-gate lgrp.lgrp_id,
4050Sstevel@tonic-gate lcc.lcc_psrsetid[i],
4060Sstevel@tonic-gate lcc.lcc_loadavg[i],
4070Sstevel@tonic-gate lcc.lcc_cpucnt[i]);
4080Sstevel@tonic-gate if (lcc.lcc_cpucnt[i])
4090Sstevel@tonic-gate print_cpuset_range(lcc.lcc_cpuset[i],
4100Sstevel@tonic-gate cpusetsize/sizeof (ulong_t), 0);
4110Sstevel@tonic-gate mdb_printf("\n");
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate return (DCMD_OK);
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate typedef struct lgrp_walk_data {
4190Sstevel@tonic-gate int lwd_nlgrps;
4200Sstevel@tonic-gate uintptr_t *lwd_lgrp_tbl;
4210Sstevel@tonic-gate int lwd_iter;
4220Sstevel@tonic-gate } lgrp_walk_data_t;
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate int
lgrp_walk_init(mdb_walk_state_t * wsp)4250Sstevel@tonic-gate lgrp_walk_init(mdb_walk_state_t *wsp)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate lgrp_walk_data_t *lwd;
4280Sstevel@tonic-gate GElf_Sym sym;
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate lwd = mdb_zalloc(sizeof (lgrp_walk_data_t), UM_SLEEP | UM_GC);
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate if (mdb_readsym(&lwd->lwd_nlgrps, sizeof (int),
4330Sstevel@tonic-gate "lgrp_alloc_max") == -1) {
4340Sstevel@tonic-gate mdb_warn("symbol 'lgrp_alloc_max' not found");
4350Sstevel@tonic-gate return (WALK_ERR);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate if (lwd->lwd_nlgrps < 0) {
4390Sstevel@tonic-gate mdb_warn("lgrp_alloc_max of bounds (%d)\n", lwd->lwd_nlgrps);
4400Sstevel@tonic-gate return (WALK_ERR);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate lwd->lwd_nlgrps++;
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate if (mdb_lookup_by_name("lgrp_table", &sym) == -1) {
4460Sstevel@tonic-gate mdb_warn("failed to find 'lgrp_table'");
4470Sstevel@tonic-gate return (WALK_ERR);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /* Get number of valid entries in lgrp_table */
4510Sstevel@tonic-gate if (sym.st_size < lwd->lwd_nlgrps * sizeof (lgrp_t *)) {
4520Sstevel@tonic-gate mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max");
4530Sstevel@tonic-gate return (WALK_ERR);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate lwd->lwd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate if (mdb_readsym(lwd->lwd_lgrp_tbl, lwd->lwd_nlgrps * sizeof (lgrp_t *),
4590Sstevel@tonic-gate "lgrp_table") == -1) {
4600Sstevel@tonic-gate mdb_warn("unable to read lgrp_table");
4610Sstevel@tonic-gate return (WALK_ERR);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate wsp->walk_data = lwd;
4660Sstevel@tonic-gate wsp->walk_addr = lwd->lwd_lgrp_tbl[0];
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate return (WALK_NEXT);
4690Sstevel@tonic-gate }
470*2685Sakolb
471*2685Sakolb /*
472*2685Sakolb * Common routine for several walkers.
473*2685Sakolb * Read lgroup from wsp->walk_addr and call wsp->walk_callback for it.
474*2685Sakolb * Normally returns the result of the callback.
475*2685Sakolb * Returns WALK_DONE if walk_addr is NULL and WALK_ERR if cannot read the
476*2685Sakolb * lgroup.
477*2685Sakolb */
478*2685Sakolb static int
lgrp_walk_step_common(mdb_walk_state_t * wsp)479*2685Sakolb lgrp_walk_step_common(mdb_walk_state_t *wsp)
480*2685Sakolb {
481*2685Sakolb lgrp_t lgrp;
482*2685Sakolb
483*2685Sakolb if (wsp->walk_addr == NULL)
484*2685Sakolb return (WALK_DONE);
485*2685Sakolb
486*2685Sakolb if (mdb_vread(&lgrp, sizeof (lgrp_t), wsp->walk_addr) == -1) {
487*2685Sakolb mdb_warn("unable to read lgrp at %p", wsp->walk_addr);
488*2685Sakolb return (WALK_ERR);
489*2685Sakolb }
490*2685Sakolb
491*2685Sakolb return (wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata));
492*2685Sakolb }
493*2685Sakolb
494*2685Sakolb /*
495*2685Sakolb * Get one lgroup from the lgroup table and adjust lwd_iter to point to the next
496*2685Sakolb * one.
497*2685Sakolb */
4980Sstevel@tonic-gate int
lgrp_walk_step(mdb_walk_state_t * wsp)4990Sstevel@tonic-gate lgrp_walk_step(mdb_walk_state_t *wsp)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate lgrp_walk_data_t *lwd = wsp->walk_data;
502*2685Sakolb int status = lgrp_walk_step_common(wsp);
503*2685Sakolb
504*2685Sakolb if (status == WALK_NEXT) {
505*2685Sakolb lwd->lwd_iter++;
506*2685Sakolb
507*2685Sakolb if (lwd->lwd_iter >= lwd->lwd_nlgrps) {
508*2685Sakolb status = WALK_DONE;
509*2685Sakolb } else {
510*2685Sakolb wsp->walk_addr = lwd->lwd_lgrp_tbl[lwd->lwd_iter];
511*2685Sakolb
512*2685Sakolb if (wsp->walk_addr == NULL) {
513*2685Sakolb mdb_warn("NULL lgrp pointer in lgrp_table[%d]",
514*2685Sakolb lwd->lwd_iter);
515*2685Sakolb return (WALK_ERR);
516*2685Sakolb }
517*2685Sakolb }
518*2685Sakolb }
519*2685Sakolb
520*2685Sakolb return (status);
521*2685Sakolb }
522*2685Sakolb
523*2685Sakolb /*
524*2685Sakolb * Initialize walker to traverse parents of lgroups. Nothing to do here.
525*2685Sakolb */
526*2685Sakolb /* ARGSUSED */
527*2685Sakolb int
lgrp_parents_walk_init(mdb_walk_state_t * wsp)528*2685Sakolb lgrp_parents_walk_init(mdb_walk_state_t *wsp)
529*2685Sakolb {
530*2685Sakolb return (WALK_NEXT);
531*2685Sakolb }
532*2685Sakolb
533*2685Sakolb /*
534*2685Sakolb * Call wsp callback on current lgroup in wsp and replace the lgroup with its
535*2685Sakolb * parent.
536*2685Sakolb */
537*2685Sakolb int
lgrp_parents_walk_step(mdb_walk_state_t * wsp)538*2685Sakolb lgrp_parents_walk_step(mdb_walk_state_t *wsp)
539*2685Sakolb {
5400Sstevel@tonic-gate lgrp_t lgrp;
5410Sstevel@tonic-gate int status;
5420Sstevel@tonic-gate
543*2685Sakolb if (wsp->walk_addr == NULL)
544*2685Sakolb return (WALK_DONE);
5450Sstevel@tonic-gate
546*2685Sakolb if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
547*2685Sakolb mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
548*2685Sakolb return (WALK_ERR);
549*2685Sakolb }
550*2685Sakolb
551*2685Sakolb status = wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata);
552*2685Sakolb
553*2685Sakolb if (status == WALK_NEXT)
554*2685Sakolb wsp->walk_addr = (uintptr_t)lgrp.lgrp_parent;
555*2685Sakolb
556*2685Sakolb return (status);
557*2685Sakolb }
558*2685Sakolb
559*2685Sakolb /*
560*2685Sakolb * Given the set return the ID of the first member of the set.
561*2685Sakolb * Returns LGRP_NONE if the set has no elements smaller than max_lgrp.
562*2685Sakolb */
563*2685Sakolb static lgrp_id_t
lgrp_set_get_first(klgrpset_t set,int max_lgrp)564*2685Sakolb lgrp_set_get_first(klgrpset_t set, int max_lgrp)
565*2685Sakolb {
566*2685Sakolb lgrp_id_t id;
567*2685Sakolb klgrpset_t bit = 1;
568*2685Sakolb
569*2685Sakolb if (set == (klgrpset_t)0)
570*2685Sakolb return (LGRP_NONE);
571*2685Sakolb
572*2685Sakolb for (id = 0; (id < max_lgrp) && !(set & bit); id++, bit <<= 1)
573*2685Sakolb ;
574*2685Sakolb
575*2685Sakolb if (id >= max_lgrp)
576*2685Sakolb id = LGRP_NONE;
577*2685Sakolb
578*2685Sakolb return (id);
579*2685Sakolb }
580*2685Sakolb
581*2685Sakolb /*
582*2685Sakolb * lgrp_set_walk_data is used to walk lgroups specified by a set.
583*2685Sakolb * On every iteration one element is removed from the set.
584*2685Sakolb */
585*2685Sakolb typedef struct lgrp_set_walk_data {
586*2685Sakolb int lswd_nlgrps; /* Number of lgroups */
587*2685Sakolb uintptr_t *lwsd_lgrp_tbl; /* Full lgroup table */
588*2685Sakolb klgrpset_t lwsd_set; /* Set of lgroups to walk */
589*2685Sakolb } lgrp_set_walk_data_t;
590*2685Sakolb
591*2685Sakolb /*
592*2685Sakolb * Initialize iterator for walkers over a set of lgroups
593*2685Sakolb */
594*2685Sakolb static int
lgrp_set_walk_init(mdb_walk_state_t * wsp,klgrpset_t set)595*2685Sakolb lgrp_set_walk_init(mdb_walk_state_t *wsp, klgrpset_t set)
596*2685Sakolb {
597*2685Sakolb lgrp_set_walk_data_t *lwsd;
598*2685Sakolb int nlgrps;
599*2685Sakolb lgrp_id_t id;
600*2685Sakolb GElf_Sym sym;
601*2685Sakolb
602*2685Sakolb /* Nothing to do if the set is empty */
603*2685Sakolb if (set == (klgrpset_t)0)
604*2685Sakolb return (WALK_DONE);
605*2685Sakolb
606*2685Sakolb lwsd = mdb_zalloc(sizeof (lgrp_set_walk_data_t), UM_SLEEP | UM_GC);
607*2685Sakolb
608*2685Sakolb /* Get the total number of lgroups */
609*2685Sakolb if (mdb_readsym(&nlgrps, sizeof (int), "lgrp_alloc_max") == -1) {
610*2685Sakolb mdb_warn("symbol 'lgrp_alloc_max' not found");
611*2685Sakolb return (WALK_ERR);
612*2685Sakolb }
613*2685Sakolb
614*2685Sakolb if (nlgrps < 0) {
615*2685Sakolb mdb_warn("lgrp_alloc_max of bounds (%d)\n", nlgrps);
6160Sstevel@tonic-gate return (WALK_ERR);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate
619*2685Sakolb nlgrps++;
6200Sstevel@tonic-gate
621*2685Sakolb /* Find ID of the first lgroup in the set */
622*2685Sakolb if ((id = lgrp_set_get_first(set, nlgrps)) == LGRP_NONE) {
623*2685Sakolb mdb_warn("No set elements within %d lgroups\n", nlgrps);
624*2685Sakolb return (WALK_ERR);
625*2685Sakolb }
6260Sstevel@tonic-gate
627*2685Sakolb /* Read lgroup_table and copy it to lwsd_lgrp_tbl */
628*2685Sakolb if (mdb_lookup_by_name("lgrp_table", &sym) == -1) {
629*2685Sakolb mdb_warn("failed to find 'lgrp_table'");
630*2685Sakolb return (WALK_ERR);
631*2685Sakolb }
6320Sstevel@tonic-gate
633*2685Sakolb /* Get number of valid entries in lgrp_table */
634*2685Sakolb if (sym.st_size < nlgrps * sizeof (lgrp_t *)) {
635*2685Sakolb mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max");
636*2685Sakolb return (WALK_ERR);
637*2685Sakolb }
6380Sstevel@tonic-gate
639*2685Sakolb lwsd->lwsd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
640*2685Sakolb lwsd->lswd_nlgrps = nlgrps;
641*2685Sakolb
642*2685Sakolb if (mdb_readsym(lwsd->lwsd_lgrp_tbl, nlgrps * sizeof (lgrp_t *),
643*2685Sakolb "lgrp_table") == -1) {
644*2685Sakolb mdb_warn("unable to read lgrp_table");
6450Sstevel@tonic-gate return (WALK_ERR);
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate
648*2685Sakolb wsp->walk_data = lwsd;
649*2685Sakolb
650*2685Sakolb /* Save the first lgroup from the set and remove it from the set */
651*2685Sakolb wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id];
652*2685Sakolb lwsd->lwsd_set = set & ~(1 << id);
653*2685Sakolb
6540Sstevel@tonic-gate return (WALK_NEXT);
6550Sstevel@tonic-gate }
656*2685Sakolb
657*2685Sakolb /*
658*2685Sakolb * Get current lgroup and advance the lgroup to the next one in the lwsd_set.
659*2685Sakolb */
660*2685Sakolb int
lgrp_set_walk_step(mdb_walk_state_t * wsp)661*2685Sakolb lgrp_set_walk_step(mdb_walk_state_t *wsp)
662*2685Sakolb {
663*2685Sakolb lgrp_id_t id = 0;
664*2685Sakolb lgrp_set_walk_data_t *lwsd = wsp->walk_data;
665*2685Sakolb int status = lgrp_walk_step_common(wsp);
666*2685Sakolb
667*2685Sakolb if (status == WALK_NEXT) {
668*2685Sakolb id = lgrp_set_get_first(lwsd->lwsd_set, lwsd->lswd_nlgrps);
669*2685Sakolb if (id == LGRP_NONE) {
670*2685Sakolb status = WALK_DONE;
671*2685Sakolb } else {
672*2685Sakolb /* Move to the next lgroup in the set */
673*2685Sakolb wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id];
674*2685Sakolb
675*2685Sakolb /* Remove id from the set */
676*2685Sakolb lwsd->lwsd_set = lwsd->lwsd_set & ~(1 << id);
677*2685Sakolb }
678*2685Sakolb }
679*2685Sakolb
680*2685Sakolb return (status);
681*2685Sakolb }
682*2685Sakolb
683*2685Sakolb /*
684*2685Sakolb * Initialize resource walker for a given lgroup and resource. The lgroup
685*2685Sakolb * address is specified in walk_addr.
686*2685Sakolb */
687*2685Sakolb static int
lgrp_rsrc_walk_init(mdb_walk_state_t * wsp,int resource)688*2685Sakolb lgrp_rsrc_walk_init(mdb_walk_state_t *wsp, int resource)
689*2685Sakolb {
690*2685Sakolb lgrp_t lgrp;
691*2685Sakolb
692*2685Sakolb if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
693*2685Sakolb mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
694*2685Sakolb return (WALK_ERR);
695*2685Sakolb }
696*2685Sakolb
697*2685Sakolb return (lgrp_set_walk_init(wsp, lgrp.lgrp_set[resource]));
698*2685Sakolb }
699*2685Sakolb
700*2685Sakolb /*
701*2685Sakolb * Initialize CPU resource walker
702*2685Sakolb */
703*2685Sakolb int
lgrp_rsrc_cpu_walk_init(mdb_walk_state_t * wsp)704*2685Sakolb lgrp_rsrc_cpu_walk_init(mdb_walk_state_t *wsp)
705*2685Sakolb {
706*2685Sakolb return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_CPU));
707*2685Sakolb }
708*2685Sakolb
709*2685Sakolb /*
710*2685Sakolb * Initialize memory resource walker
711*2685Sakolb */
712*2685Sakolb int
lgrp_rsrc_mem_walk_init(mdb_walk_state_t * wsp)713*2685Sakolb lgrp_rsrc_mem_walk_init(mdb_walk_state_t *wsp)
714*2685Sakolb {
715*2685Sakolb return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_MEM));
716*2685Sakolb }
717*2685Sakolb
718*2685Sakolb /*
719*2685Sakolb * Display bitmap as a list of integers
720*2685Sakolb */
721*2685Sakolb /* ARGSUSED */
722*2685Sakolb int
lgrp_set(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)723*2685Sakolb lgrp_set(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
724*2685Sakolb {
725*2685Sakolb uint64_t set = (uint64_t)addr;
726*2685Sakolb uint64_t mask = 1;
727*2685Sakolb int i = 0;
728*2685Sakolb
729*2685Sakolb if (!(flags & DCMD_ADDRSPEC)) {
730*2685Sakolb return (DCMD_USAGE);
731*2685Sakolb }
732*2685Sakolb
733*2685Sakolb if (set == 0)
734*2685Sakolb return (DCMD_OK);
735*2685Sakolb
736*2685Sakolb for (; set != (uint64_t)0; i++, mask <<= 1) {
737*2685Sakolb if (set & mask) {
738*2685Sakolb mdb_printf("%d ", i);
739*2685Sakolb set &= ~mask;
740*2685Sakolb }
741*2685Sakolb }
742*2685Sakolb mdb_printf("\n");
743*2685Sakolb return (DCMD_OK);
744*2685Sakolb }
745