1*7aec1d6eScindi /* 2*7aec1d6eScindi * CDDL HEADER START 3*7aec1d6eScindi * 4*7aec1d6eScindi * The contents of this file are subject to the terms of the 5*7aec1d6eScindi * Common Development and Distribution License (the "License"). 6*7aec1d6eScindi * You may not use this file except in compliance with the License. 7*7aec1d6eScindi * 8*7aec1d6eScindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7aec1d6eScindi * or http://www.opensolaris.org/os/licensing. 10*7aec1d6eScindi * See the License for the specific language governing permissions 11*7aec1d6eScindi * and limitations under the License. 12*7aec1d6eScindi * 13*7aec1d6eScindi * When distributing Covered Code, include this CDDL HEADER in each 14*7aec1d6eScindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7aec1d6eScindi * If applicable, add the following below this CDDL HEADER, with the 16*7aec1d6eScindi * fields enclosed by brackets "[]" replaced with your own identifying 17*7aec1d6eScindi * information: Portions Copyright [yyyy] [name of copyright owner] 18*7aec1d6eScindi * 19*7aec1d6eScindi * CDDL HEADER END 20*7aec1d6eScindi */ 21*7aec1d6eScindi 22*7aec1d6eScindi /* 23*7aec1d6eScindi * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*7aec1d6eScindi * Use is subject to license terms. 25*7aec1d6eScindi */ 26*7aec1d6eScindi 27*7aec1d6eScindi #pragma ident "%Z%%M% %I% %E% SMI" 28*7aec1d6eScindi 29*7aec1d6eScindi #include <unistd.h> 30*7aec1d6eScindi #include <stdio.h> 31*7aec1d6eScindi #include <stdlib.h> 32*7aec1d6eScindi #include <string.h> 33*7aec1d6eScindi #include <strings.h> 34*7aec1d6eScindi #include <limits.h> 35*7aec1d6eScindi #include <alloca.h> 36*7aec1d6eScindi #include <kstat.h> 37*7aec1d6eScindi #include <fcntl.h> 38*7aec1d6eScindi #include <errno.h> 39*7aec1d6eScindi #include <libnvpair.h> 40*7aec1d6eScindi #include <sys/types.h> 41*7aec1d6eScindi #include <sys/bitmap.h> 42*7aec1d6eScindi #include <sys/processor.h> 43*7aec1d6eScindi #include <sys/param.h> 44*7aec1d6eScindi #include <sys/fm/protocol.h> 45*7aec1d6eScindi #include <sys/systeminfo.h> 46*7aec1d6eScindi #include <sys/mc.h> 47*7aec1d6eScindi #include <fm/topo_mod.h> 48*7aec1d6eScindi 49*7aec1d6eScindi #include "chip.h" 50*7aec1d6eScindi 51*7aec1d6eScindi #ifndef MAX 52*7aec1d6eScindi #define MAX(a, b) ((a) > (b) ? (a) : (b)) 53*7aec1d6eScindi #endif 54*7aec1d6eScindi 55*7aec1d6eScindi /* 56*7aec1d6eScindi * Enumerates the processing chips, or sockets, (as distinct from cores) in a 57*7aec1d6eScindi * system. For each chip found, the necessary nodes (one or more cores, and 58*7aec1d6eScindi * possibly a memory controller) are constructed underneath. 59*7aec1d6eScindi */ 60*7aec1d6eScindi 61*7aec1d6eScindi static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 62*7aec1d6eScindi topo_instance_t, void *); 63*7aec1d6eScindi 64*7aec1d6eScindi const topo_modinfo_t chip_info = 65*7aec1d6eScindi { "chip", CHIP_VERSION, chip_enum, NULL}; 66*7aec1d6eScindi 67*7aec1d6eScindi int 68*7aec1d6eScindi _topo_init(topo_mod_t *mod) 69*7aec1d6eScindi { 70*7aec1d6eScindi chip_t *chip; 71*7aec1d6eScindi 72*7aec1d6eScindi topo_mod_setdebug(mod, TOPO_DBG_ALL); 73*7aec1d6eScindi topo_mod_dprintf(mod, "initializing chip enumerator\n"); 74*7aec1d6eScindi 75*7aec1d6eScindi if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 76*7aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_NOMEM)); 77*7aec1d6eScindi 78*7aec1d6eScindi if ((chip->chip_kc = kstat_open()) == NULL) { 79*7aec1d6eScindi topo_mod_dprintf(mod, "kstat_open failed: %s\n", 80*7aec1d6eScindi strerror(errno)); 81*7aec1d6eScindi topo_mod_free(mod, chip, sizeof (chip_t)); 82*7aec1d6eScindi return (topo_mod_seterrno(mod, errno)); 83*7aec1d6eScindi } 84*7aec1d6eScindi 85*7aec1d6eScindi chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); 86*7aec1d6eScindi if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( 87*7aec1d6eScindi chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 88*7aec1d6eScindi (void) kstat_close(chip->chip_kc); 89*7aec1d6eScindi topo_mod_free(mod, chip, sizeof (chip_t)); 90*7aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_NOMEM)); 91*7aec1d6eScindi } 92*7aec1d6eScindi 93*7aec1d6eScindi if (topo_mod_register(mod, &chip_info, (void *)chip) != 0) { 94*7aec1d6eScindi topo_mod_dprintf(mod, "failed to register hc: " 95*7aec1d6eScindi "%s\n", topo_mod_errmsg(mod)); 96*7aec1d6eScindi topo_mod_free(mod, chip->chip_cpustats, 97*7aec1d6eScindi (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 98*7aec1d6eScindi (void) kstat_close(chip->chip_kc); 99*7aec1d6eScindi topo_mod_free(mod, chip, sizeof (chip_t)); 100*7aec1d6eScindi return (-1); /* mod errno set */ 101*7aec1d6eScindi } 102*7aec1d6eScindi 103*7aec1d6eScindi return (0); 104*7aec1d6eScindi } 105*7aec1d6eScindi 106*7aec1d6eScindi void 107*7aec1d6eScindi _topo_fini(topo_mod_t *mod) 108*7aec1d6eScindi { 109*7aec1d6eScindi chip_t *chip = topo_mod_private(mod); 110*7aec1d6eScindi 111*7aec1d6eScindi if (chip->chip_cpustats != NULL) 112*7aec1d6eScindi topo_mod_free(mod, chip->chip_cpustats, 113*7aec1d6eScindi (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 114*7aec1d6eScindi 115*7aec1d6eScindi (void) kstat_close(chip->chip_kc); 116*7aec1d6eScindi topo_mod_free(mod, chip, sizeof (chip_t)); 117*7aec1d6eScindi 118*7aec1d6eScindi topo_mod_unregister(mod); 119*7aec1d6eScindi } 120*7aec1d6eScindi 121*7aec1d6eScindi static int 122*7aec1d6eScindi chip_strprop(tnode_t *cnode, kstat_t *ksp, const char *name) 123*7aec1d6eScindi { 124*7aec1d6eScindi int err; 125*7aec1d6eScindi kstat_named_t *k; 126*7aec1d6eScindi 127*7aec1d6eScindi if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) 128*7aec1d6eScindi return (0); 129*7aec1d6eScindi 130*7aec1d6eScindi (void) topo_prop_set_string(cnode, CHIP_PGROUP, name, 131*7aec1d6eScindi TOPO_PROP_SET_ONCE, k->value.str.addr.ptr, &err); 132*7aec1d6eScindi 133*7aec1d6eScindi return (-1); 134*7aec1d6eScindi } 135*7aec1d6eScindi 136*7aec1d6eScindi static int 137*7aec1d6eScindi chip_longprop(tnode_t *cnode, kstat_t *ksp, const char *name) 138*7aec1d6eScindi { 139*7aec1d6eScindi int err; 140*7aec1d6eScindi kstat_named_t *k; 141*7aec1d6eScindi 142*7aec1d6eScindi if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) 143*7aec1d6eScindi return (0); 144*7aec1d6eScindi 145*7aec1d6eScindi (void) topo_prop_set_int32(cnode, CHIP_PGROUP, name, TOPO_PROP_SET_ONCE, 146*7aec1d6eScindi k->value.l, &err); 147*7aec1d6eScindi 148*7aec1d6eScindi return (-1); 149*7aec1d6eScindi } 150*7aec1d6eScindi 151*7aec1d6eScindi static nvlist_t * 152*7aec1d6eScindi cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask) 153*7aec1d6eScindi { 154*7aec1d6eScindi int err; 155*7aec1d6eScindi nvlist_t *asru; 156*7aec1d6eScindi 157*7aec1d6eScindi if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 158*7aec1d6eScindi return (NULL); 159*7aec1d6eScindi 160*7aec1d6eScindi err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION); 161*7aec1d6eScindi err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 162*7aec1d6eScindi err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid); 163*7aec1d6eScindi err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask); 164*7aec1d6eScindi if (s != NULL) 165*7aec1d6eScindi err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s); 166*7aec1d6eScindi if (err != 0) { 167*7aec1d6eScindi nvlist_free(asru); 168*7aec1d6eScindi (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 169*7aec1d6eScindi return (NULL); 170*7aec1d6eScindi } 171*7aec1d6eScindi 172*7aec1d6eScindi return (asru); 173*7aec1d6eScindi } 174*7aec1d6eScindi 175*7aec1d6eScindi static int 176*7aec1d6eScindi cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 177*7aec1d6eScindi chip_t *chip) 178*7aec1d6eScindi { 179*7aec1d6eScindi kstat_named_t *k; 180*7aec1d6eScindi topo_hdl_t *thp; 181*7aec1d6eScindi nvlist_t *fmri, *pfmri, *asru, *args; 182*7aec1d6eScindi tnode_t *cnode; 183*7aec1d6eScindi int i, err, nerr = 0; 184*7aec1d6eScindi 185*7aec1d6eScindi if (topo_node_range_create(mod, pnode, name, 0, 186*7aec1d6eScindi chip->chip_ncpustats) < 0) 187*7aec1d6eScindi return (-1); 188*7aec1d6eScindi 189*7aec1d6eScindi thp = topo_mod_handle(mod); 190*7aec1d6eScindi 191*7aec1d6eScindi for (i = 0; i <= chip->chip_ncpustats; i++) { 192*7aec1d6eScindi 193*7aec1d6eScindi if (chip->chip_cpustats[i] == NULL) 194*7aec1d6eScindi continue; 195*7aec1d6eScindi 196*7aec1d6eScindi if ((k = kstat_data_lookup(chip->chip_cpustats[i], "chip_id")) 197*7aec1d6eScindi == NULL || k->value.l != chipid) { 198*7aec1d6eScindi ++nerr; 199*7aec1d6eScindi continue; 200*7aec1d6eScindi } 201*7aec1d6eScindi 202*7aec1d6eScindi if ((k = kstat_data_lookup(chip->chip_cpustats[i], "clog_id")) 203*7aec1d6eScindi == NULL) { 204*7aec1d6eScindi ++nerr; 205*7aec1d6eScindi continue; 206*7aec1d6eScindi } 207*7aec1d6eScindi 208*7aec1d6eScindi args = pfmri = NULL; 209*7aec1d6eScindi if (topo_node_resource(pnode, &pfmri, &err) < 0 || 210*7aec1d6eScindi topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 211*7aec1d6eScindi nvlist_add_nvlist(args, 212*7aec1d6eScindi TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 213*7aec1d6eScindi nvlist_free(pfmri); 214*7aec1d6eScindi nvlist_free(args); 215*7aec1d6eScindi ++nerr; 216*7aec1d6eScindi continue; 217*7aec1d6eScindi } 218*7aec1d6eScindi 219*7aec1d6eScindi fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 220*7aec1d6eScindi (topo_instance_t)k->value.l, args, &err); 221*7aec1d6eScindi nvlist_free(pfmri); 222*7aec1d6eScindi nvlist_free(args); 223*7aec1d6eScindi if (fmri == NULL) { 224*7aec1d6eScindi ++nerr; 225*7aec1d6eScindi continue; 226*7aec1d6eScindi } 227*7aec1d6eScindi 228*7aec1d6eScindi if ((cnode = topo_node_bind(mod, pnode, name, i, fmri, 229*7aec1d6eScindi NULL)) == NULL) { 230*7aec1d6eScindi ++nerr; 231*7aec1d6eScindi nvlist_free(fmri); 232*7aec1d6eScindi continue; 233*7aec1d6eScindi } 234*7aec1d6eScindi nvlist_free(fmri); 235*7aec1d6eScindi 236*7aec1d6eScindi if ((asru = cpu_fmri_create(mod, i, NULL, 0)) != NULL) { 237*7aec1d6eScindi (void) topo_node_asru_set(cnode, asru, 0, &err); 238*7aec1d6eScindi nvlist_free(asru); 239*7aec1d6eScindi } else { 240*7aec1d6eScindi ++nerr; 241*7aec1d6eScindi } 242*7aec1d6eScindi (void) topo_node_fru_set(cnode, NULL, 0, &err); 243*7aec1d6eScindi } 244*7aec1d6eScindi 245*7aec1d6eScindi if (nerr != 0) 246*7aec1d6eScindi return (-1); 247*7aec1d6eScindi else 248*7aec1d6eScindi return (0); 249*7aec1d6eScindi } 250*7aec1d6eScindi 251*7aec1d6eScindi static int 252*7aec1d6eScindi nvprop_add(nvpair_t *nvp, const char *pgname, tnode_t *node) 253*7aec1d6eScindi { 254*7aec1d6eScindi int err; 255*7aec1d6eScindi char *pname = nvpair_name(nvp); 256*7aec1d6eScindi 257*7aec1d6eScindi switch (nvpair_type(nvp)) { 258*7aec1d6eScindi case DATA_TYPE_BOOLEAN_VALUE: { 259*7aec1d6eScindi boolean_t val; 260*7aec1d6eScindi 261*7aec1d6eScindi if (nvpair_value_boolean_value(nvp, &val) == 0) { 262*7aec1d6eScindi (void) topo_prop_set_string(node, pgname, pname, 263*7aec1d6eScindi TOPO_PROP_SET_ONCE, (val ? "true" : "false"), &err); 264*7aec1d6eScindi } 265*7aec1d6eScindi return (0); 266*7aec1d6eScindi } 267*7aec1d6eScindi 268*7aec1d6eScindi case DATA_TYPE_UINT64: { 269*7aec1d6eScindi uint64_t val; 270*7aec1d6eScindi 271*7aec1d6eScindi if (nvpair_value_uint64(nvp, &val) == 0) { 272*7aec1d6eScindi (void) topo_prop_set_uint64(node, pgname, pname, 273*7aec1d6eScindi TOPO_PROP_SET_ONCE, val, &err); 274*7aec1d6eScindi } 275*7aec1d6eScindi return (0); 276*7aec1d6eScindi } 277*7aec1d6eScindi 278*7aec1d6eScindi case DATA_TYPE_STRING: { 279*7aec1d6eScindi char *str; 280*7aec1d6eScindi 281*7aec1d6eScindi if (nvpair_value_string(nvp, &str) == 0) 282*7aec1d6eScindi (void) topo_prop_set_string(node, pgname, pname, 283*7aec1d6eScindi TOPO_PROP_SET_ONCE, str, &err); 284*7aec1d6eScindi return (0); 285*7aec1d6eScindi } 286*7aec1d6eScindi 287*7aec1d6eScindi default: 288*7aec1d6eScindi return (-1); 289*7aec1d6eScindi } 290*7aec1d6eScindi } 291*7aec1d6eScindi 292*7aec1d6eScindi nvlist_t * 293*7aec1d6eScindi mem_fmri_create(topo_mod_t *mod) 294*7aec1d6eScindi { 295*7aec1d6eScindi nvlist_t *asru; 296*7aec1d6eScindi 297*7aec1d6eScindi if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 298*7aec1d6eScindi return (NULL); 299*7aec1d6eScindi 300*7aec1d6eScindi if (nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0 || 301*7aec1d6eScindi nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION) != 0) { 302*7aec1d6eScindi nvlist_free(asru); 303*7aec1d6eScindi return (NULL); 304*7aec1d6eScindi } 305*7aec1d6eScindi 306*7aec1d6eScindi return (asru); 307*7aec1d6eScindi } 308*7aec1d6eScindi 309*7aec1d6eScindi static int 310*7aec1d6eScindi cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) 311*7aec1d6eScindi { 312*7aec1d6eScindi int i, err, nerr = 0; 313*7aec1d6eScindi nvpair_t *nvp; 314*7aec1d6eScindi tnode_t *csnode; 315*7aec1d6eScindi topo_hdl_t *thp; 316*7aec1d6eScindi nvlist_t *fmri, **csarr = NULL; 317*7aec1d6eScindi nvlist_t *pfmri, *args; 318*7aec1d6eScindi uint64_t csnum; 319*7aec1d6eScindi uint_t ncs; 320*7aec1d6eScindi 321*7aec1d6eScindi if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) 322*7aec1d6eScindi return (-1); 323*7aec1d6eScindi 324*7aec1d6eScindi if (topo_node_range_create(mod, pnode, name, 0, ncs) < 0) 325*7aec1d6eScindi return (-1); 326*7aec1d6eScindi 327*7aec1d6eScindi thp = topo_mod_handle(mod); 328*7aec1d6eScindi for (i = 0; i < ncs; i++) { 329*7aec1d6eScindi if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { 330*7aec1d6eScindi ++nerr; 331*7aec1d6eScindi continue; 332*7aec1d6eScindi } 333*7aec1d6eScindi 334*7aec1d6eScindi args = pfmri = NULL; 335*7aec1d6eScindi if (topo_node_resource(pnode, &pfmri, &err) < 0 || 336*7aec1d6eScindi topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 337*7aec1d6eScindi nvlist_add_nvlist(args, 338*7aec1d6eScindi TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 339*7aec1d6eScindi nvlist_free(pfmri); 340*7aec1d6eScindi nvlist_free(args); 341*7aec1d6eScindi ++nerr; 342*7aec1d6eScindi continue; 343*7aec1d6eScindi } 344*7aec1d6eScindi fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 345*7aec1d6eScindi csnum, args, &err); 346*7aec1d6eScindi nvlist_free(pfmri); 347*7aec1d6eScindi nvlist_free(args); 348*7aec1d6eScindi if (fmri == NULL) { 349*7aec1d6eScindi ++nerr; 350*7aec1d6eScindi continue; 351*7aec1d6eScindi } 352*7aec1d6eScindi 353*7aec1d6eScindi if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri, 354*7aec1d6eScindi NULL)) == NULL) { 355*7aec1d6eScindi nvlist_free(fmri); 356*7aec1d6eScindi ++nerr; 357*7aec1d6eScindi continue; 358*7aec1d6eScindi } 359*7aec1d6eScindi 360*7aec1d6eScindi nvlist_free(fmri); 361*7aec1d6eScindi 362*7aec1d6eScindi (void) topo_pgroup_create(csnode, CS_PGROUP, 363*7aec1d6eScindi TOPO_STABILITY_PRIVATE, &err); 364*7aec1d6eScindi 365*7aec1d6eScindi for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; 366*7aec1d6eScindi nvp = nvlist_next_nvpair(csarr[i], nvp)) { 367*7aec1d6eScindi (void) nvprop_add(nvp, CS_PGROUP, csnode); 368*7aec1d6eScindi } 369*7aec1d6eScindi } 370*7aec1d6eScindi 371*7aec1d6eScindi if (nerr != 0) 372*7aec1d6eScindi return (-1); 373*7aec1d6eScindi else 374*7aec1d6eScindi return (0); 375*7aec1d6eScindi } 376*7aec1d6eScindi 377*7aec1d6eScindi static int 378*7aec1d6eScindi dimm_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) 379*7aec1d6eScindi { 380*7aec1d6eScindi int i, err, nerr = 0; 381*7aec1d6eScindi nvpair_t *nvp; 382*7aec1d6eScindi tnode_t *dimmnode; 383*7aec1d6eScindi nvlist_t *fmri, *asru, **dimmarr = NULL; 384*7aec1d6eScindi nvlist_t *pfmri, *args; 385*7aec1d6eScindi uint64_t ldimmnum; 386*7aec1d6eScindi uint_t ndimm; 387*7aec1d6eScindi topo_hdl_t *thp; 388*7aec1d6eScindi 389*7aec1d6eScindi thp = topo_mod_handle(mod); 390*7aec1d6eScindi 391*7aec1d6eScindi if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) 392*7aec1d6eScindi return (-1); 393*7aec1d6eScindi 394*7aec1d6eScindi if (topo_node_range_create(mod, pnode, name, 0, ndimm) < 0) 395*7aec1d6eScindi return (-1); 396*7aec1d6eScindi 397*7aec1d6eScindi for (i = 0; i < ndimm; i++) { 398*7aec1d6eScindi if (nvlist_lookup_uint64(dimmarr[i], "num", &ldimmnum) != 0) { 399*7aec1d6eScindi ++nerr; 400*7aec1d6eScindi continue; 401*7aec1d6eScindi } 402*7aec1d6eScindi 403*7aec1d6eScindi args = pfmri = NULL; 404*7aec1d6eScindi if (topo_node_resource(pnode, &pfmri, &err) < 0 || 405*7aec1d6eScindi topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 406*7aec1d6eScindi nvlist_add_nvlist(args, 407*7aec1d6eScindi TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 408*7aec1d6eScindi nvlist_free(pfmri); 409*7aec1d6eScindi nvlist_free(args); 410*7aec1d6eScindi ++nerr; 411*7aec1d6eScindi continue; 412*7aec1d6eScindi } 413*7aec1d6eScindi fmri = topo_fmri_create(thp, 414*7aec1d6eScindi FM_FMRI_SCHEME_HC, name, ldimmnum, args, &err); 415*7aec1d6eScindi nvlist_free(pfmri); 416*7aec1d6eScindi nvlist_free(args); 417*7aec1d6eScindi if (fmri == NULL) { 418*7aec1d6eScindi ++nerr; 419*7aec1d6eScindi continue; 420*7aec1d6eScindi } 421*7aec1d6eScindi 422*7aec1d6eScindi if ((dimmnode = topo_node_bind(mod, pnode, name, ldimmnum, fmri, 423*7aec1d6eScindi NULL)) == NULL) { 424*7aec1d6eScindi nvlist_free(fmri); 425*7aec1d6eScindi ++nerr; 426*7aec1d6eScindi continue; 427*7aec1d6eScindi } 428*7aec1d6eScindi 429*7aec1d6eScindi (void) topo_node_fru_set(dimmnode, fmri, 0, &err); 430*7aec1d6eScindi if ((asru = mem_fmri_create(mod)) != NULL) { 431*7aec1d6eScindi (void) topo_node_asru_set(dimmnode, asru, 432*7aec1d6eScindi TOPO_ASRU_COMPUTE, &err); 433*7aec1d6eScindi nvlist_free(asru); 434*7aec1d6eScindi } 435*7aec1d6eScindi 436*7aec1d6eScindi nvlist_free(fmri); 437*7aec1d6eScindi 438*7aec1d6eScindi (void) topo_pgroup_create(dimmnode, DIMM_PGROUP, 439*7aec1d6eScindi TOPO_STABILITY_PRIVATE, &err); 440*7aec1d6eScindi 441*7aec1d6eScindi for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; 442*7aec1d6eScindi nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { 443*7aec1d6eScindi if (nvprop_add(nvp, DIMM_PGROUP, dimmnode) == 0) { 444*7aec1d6eScindi continue; 445*7aec1d6eScindi } else if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY) { 446*7aec1d6eScindi uint64_t *csnumarr; 447*7aec1d6eScindi uint_t ncs; 448*7aec1d6eScindi int i; 449*7aec1d6eScindi 450*7aec1d6eScindi if (strcmp(nvpair_name(nvp), "csnums") != 0 || 451*7aec1d6eScindi nvpair_value_uint64_array(nvp, &csnumarr, 452*7aec1d6eScindi &ncs) != 0) 453*7aec1d6eScindi continue; 454*7aec1d6eScindi 455*7aec1d6eScindi for (i = 0; i < ncs; i++) { 456*7aec1d6eScindi char name[7]; 457*7aec1d6eScindi (void) snprintf(name, sizeof (name), 458*7aec1d6eScindi "csnum%d", i); 459*7aec1d6eScindi (void) topo_prop_set_uint64(dimmnode, 460*7aec1d6eScindi DIMM_PGROUP, name, 461*7aec1d6eScindi TOPO_PROP_SET_ONCE, 462*7aec1d6eScindi csnumarr[i], &err); 463*7aec1d6eScindi } 464*7aec1d6eScindi } 465*7aec1d6eScindi } 466*7aec1d6eScindi } 467*7aec1d6eScindi 468*7aec1d6eScindi if (nerr != 0) 469*7aec1d6eScindi return (-1); 470*7aec1d6eScindi else 471*7aec1d6eScindi return (0); 472*7aec1d6eScindi } 473*7aec1d6eScindi 474*7aec1d6eScindi static nvlist_t * 475*7aec1d6eScindi mc_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) 476*7aec1d6eScindi { 477*7aec1d6eScindi mc_snapshot_info_t mcs; 478*7aec1d6eScindi void *buf = NULL; 479*7aec1d6eScindi 480*7aec1d6eScindi nvlist_t *nvl; 481*7aec1d6eScindi char path[64]; 482*7aec1d6eScindi int fd, err; 483*7aec1d6eScindi 484*7aec1d6eScindi (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 485*7aec1d6eScindi fd = open(path, O_RDONLY); 486*7aec1d6eScindi 487*7aec1d6eScindi if (fd == -1) { 488*7aec1d6eScindi topo_mod_dprintf(mod, "mc failed to open %s: %s\n", 489*7aec1d6eScindi path, strerror(errno)); 490*7aec1d6eScindi return (NULL); 491*7aec1d6eScindi } 492*7aec1d6eScindi 493*7aec1d6eScindi if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 494*7aec1d6eScindi (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 495*7aec1d6eScindi ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { 496*7aec1d6eScindi 497*7aec1d6eScindi topo_mod_dprintf(mod, "mc failed to snapshot %s: %s\n", 498*7aec1d6eScindi path, strerror(errno)); 499*7aec1d6eScindi 500*7aec1d6eScindi free(buf); 501*7aec1d6eScindi (void) close(fd); 502*7aec1d6eScindi return (NULL); 503*7aec1d6eScindi } 504*7aec1d6eScindi 505*7aec1d6eScindi (void) close(fd); 506*7aec1d6eScindi err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 507*7aec1d6eScindi topo_mod_free(mod, buf, mcs.mcs_size); 508*7aec1d6eScindi return (err ? NULL : nvl); 509*7aec1d6eScindi } 510*7aec1d6eScindi 511*7aec1d6eScindi static int 512*7aec1d6eScindi mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name) 513*7aec1d6eScindi { 514*7aec1d6eScindi int err, rc = 0; 515*7aec1d6eScindi tnode_t *mcnode; 516*7aec1d6eScindi nvlist_t *fmri; 517*7aec1d6eScindi nvpair_t *nvp; 518*7aec1d6eScindi nvlist_t *mc = NULL; 519*7aec1d6eScindi nvlist_t *pfmri, *args; 520*7aec1d6eScindi topo_hdl_t *thp; 521*7aec1d6eScindi 522*7aec1d6eScindi thp = topo_mod_handle(mod); 523*7aec1d6eScindi args = pfmri = NULL; 524*7aec1d6eScindi if (topo_node_resource(pnode, &pfmri, &err) < 0 || 525*7aec1d6eScindi topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 526*7aec1d6eScindi nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 527*7aec1d6eScindi nvlist_free(pfmri); 528*7aec1d6eScindi nvlist_free(args); 529*7aec1d6eScindi return (-1); 530*7aec1d6eScindi } 531*7aec1d6eScindi fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 0, args, &err); 532*7aec1d6eScindi nvlist_free(pfmri); 533*7aec1d6eScindi nvlist_free(args); 534*7aec1d6eScindi if (fmri == NULL) 535*7aec1d6eScindi return (-1); 536*7aec1d6eScindi 537*7aec1d6eScindi if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) { 538*7aec1d6eScindi nvlist_free(fmri); 539*7aec1d6eScindi return (-1); 540*7aec1d6eScindi } 541*7aec1d6eScindi 542*7aec1d6eScindi /* 543*7aec1d6eScindi * Gather and create memory controller topology 544*7aec1d6eScindi */ 545*7aec1d6eScindi if ((mc = mc_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL || 546*7aec1d6eScindi (mcnode = topo_node_bind(mod, pnode, 547*7aec1d6eScindi name, 0, fmri, NULL)) == NULL) { 548*7aec1d6eScindi if (mc != NULL) 549*7aec1d6eScindi nvlist_free(mc); 550*7aec1d6eScindi topo_node_range_destroy(pnode, name); 551*7aec1d6eScindi nvlist_free(fmri); 552*7aec1d6eScindi return (-1); 553*7aec1d6eScindi } 554*7aec1d6eScindi 555*7aec1d6eScindi (void) topo_node_fru_set(mcnode, NULL, 0, &err); 556*7aec1d6eScindi nvlist_free(fmri); 557*7aec1d6eScindi 558*7aec1d6eScindi /* 559*7aec1d6eScindi * Add memory controller properties 560*7aec1d6eScindi */ 561*7aec1d6eScindi (void) topo_pgroup_create(mcnode, MC_PGROUP, 562*7aec1d6eScindi TOPO_STABILITY_PRIVATE, &err); 563*7aec1d6eScindi 564*7aec1d6eScindi for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; 565*7aec1d6eScindi nvp = nvlist_next_nvpair(mc, nvp)) { 566*7aec1d6eScindi if (nvprop_add(nvp, MC_PGROUP, mcnode) == 0) 567*7aec1d6eScindi continue; 568*7aec1d6eScindi else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) 569*7aec1d6eScindi break; 570*7aec1d6eScindi } 571*7aec1d6eScindi 572*7aec1d6eScindi if (dimm_create(mod, mcnode, DIMM_NODE_NAME, mc) != 0 || 573*7aec1d6eScindi cs_create(mod, mcnode, CS_NODE_NAME, mc) != 0) 574*7aec1d6eScindi rc = -1; 575*7aec1d6eScindi 576*7aec1d6eScindi nvlist_free(mc); 577*7aec1d6eScindi return (rc); 578*7aec1d6eScindi } 579*7aec1d6eScindi 580*7aec1d6eScindi static int 581*7aec1d6eScindi chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 582*7aec1d6eScindi topo_instance_t min, topo_instance_t max, chip_t *chip) 583*7aec1d6eScindi { 584*7aec1d6eScindi int i, nerr = 0; 585*7aec1d6eScindi kstat_t *ksp; 586*7aec1d6eScindi ulong_t *chipmap; 587*7aec1d6eScindi tnode_t *cnode; 588*7aec1d6eScindi nvlist_t *pfmri, *fmri, *args; 589*7aec1d6eScindi topo_hdl_t *thp; 590*7aec1d6eScindi 591*7aec1d6eScindi thp = topo_mod_handle(mod); 592*7aec1d6eScindi 593*7aec1d6eScindi if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(chip->chip_ncpustats) * 594*7aec1d6eScindi sizeof (ulong_t))) == NULL) 595*7aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_NOMEM)); 596*7aec1d6eScindi 597*7aec1d6eScindi for (i = min; i <= MAX(max, chip->chip_ncpustats); i++) { 598*7aec1d6eScindi 599*7aec1d6eScindi if (i < min || i > max) 600*7aec1d6eScindi break; 601*7aec1d6eScindi 602*7aec1d6eScindi if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == 603*7aec1d6eScindi NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) 604*7aec1d6eScindi continue; 605*7aec1d6eScindi 606*7aec1d6eScindi chip->chip_cpustats[i] = ksp; 607*7aec1d6eScindi } 608*7aec1d6eScindi 609*7aec1d6eScindi for (i = 0; i <= chip->chip_ncpustats; i++) { 610*7aec1d6eScindi kstat_named_t *k; 611*7aec1d6eScindi int err, chipid; 612*7aec1d6eScindi 613*7aec1d6eScindi if ((ksp = chip->chip_cpustats[i]) == NULL) 614*7aec1d6eScindi continue; 615*7aec1d6eScindi 616*7aec1d6eScindi if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { 617*7aec1d6eScindi ++nerr; 618*7aec1d6eScindi continue; 619*7aec1d6eScindi } 620*7aec1d6eScindi 621*7aec1d6eScindi chipid = k->value.l; 622*7aec1d6eScindi if (BT_TEST(chipmap, chipid)) 623*7aec1d6eScindi continue; 624*7aec1d6eScindi 625*7aec1d6eScindi if (chipid < min || chipid > max) 626*7aec1d6eScindi continue; 627*7aec1d6eScindi 628*7aec1d6eScindi args = pfmri = NULL; 629*7aec1d6eScindi if (topo_node_resource(pnode, &pfmri, &err) < 0 || 630*7aec1d6eScindi topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 631*7aec1d6eScindi nvlist_add_nvlist(args, 632*7aec1d6eScindi TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 633*7aec1d6eScindi nvlist_free(pfmri); 634*7aec1d6eScindi nvlist_free(args); 635*7aec1d6eScindi ++nerr; 636*7aec1d6eScindi continue; 637*7aec1d6eScindi } 638*7aec1d6eScindi fmri = topo_fmri_create(thp, 639*7aec1d6eScindi FM_FMRI_SCHEME_HC, name, chipid, args, &err); 640*7aec1d6eScindi nvlist_free(pfmri); 641*7aec1d6eScindi nvlist_free(args); 642*7aec1d6eScindi if (fmri == NULL) { 643*7aec1d6eScindi ++nerr; 644*7aec1d6eScindi continue; 645*7aec1d6eScindi } 646*7aec1d6eScindi 647*7aec1d6eScindi if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri, 648*7aec1d6eScindi NULL)) == NULL) { 649*7aec1d6eScindi ++nerr; 650*7aec1d6eScindi nvlist_free(fmri); 651*7aec1d6eScindi continue; 652*7aec1d6eScindi } 653*7aec1d6eScindi 654*7aec1d6eScindi (void) topo_node_fru_set(cnode, fmri, 0, &err); 655*7aec1d6eScindi 656*7aec1d6eScindi nvlist_free(fmri); 657*7aec1d6eScindi 658*7aec1d6eScindi (void) topo_pgroup_create(cnode, CHIP_PGROUP, 659*7aec1d6eScindi TOPO_STABILITY_PRIVATE, &err); 660*7aec1d6eScindi (void) chip_strprop(cnode, ksp, CHIP_VENDOR_ID); 661*7aec1d6eScindi (void) chip_longprop(cnode, ksp, CHIP_FAMILY); 662*7aec1d6eScindi (void) chip_longprop(cnode, ksp, CHIP_MODEL); 663*7aec1d6eScindi (void) chip_longprop(cnode, ksp, CHIP_STEPPING); 664*7aec1d6eScindi 665*7aec1d6eScindi if (mc_create(mod, cnode, MC_NODE_NAME) != 0 || 666*7aec1d6eScindi cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip) != 0) 667*7aec1d6eScindi ++nerr; 668*7aec1d6eScindi } 669*7aec1d6eScindi 670*7aec1d6eScindi topo_mod_free(mod, chipmap, BT_BITOUL(chip->chip_ncpustats) * 671*7aec1d6eScindi sizeof (ulong_t)); 672*7aec1d6eScindi 673*7aec1d6eScindi if (nerr != 0) 674*7aec1d6eScindi (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 675*7aec1d6eScindi 676*7aec1d6eScindi return (0); 677*7aec1d6eScindi } 678*7aec1d6eScindi 679*7aec1d6eScindi static int 680*7aec1d6eScindi chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 681*7aec1d6eScindi topo_instance_t min, topo_instance_t max, void *arg) 682*7aec1d6eScindi { 683*7aec1d6eScindi chip_t *chip = (chip_t *)arg; 684*7aec1d6eScindi 685*7aec1d6eScindi if (strcmp(name, "chip") == 0) 686*7aec1d6eScindi return (chip_create(mod, pnode, name, min, max, chip)); 687*7aec1d6eScindi 688*7aec1d6eScindi return (0); 689*7aec1d6eScindi } 690