120c794b3Sgavinm /* 220c794b3Sgavinm * CDDL HEADER START 320c794b3Sgavinm * 420c794b3Sgavinm * The contents of this file are subject to the terms of the 520c794b3Sgavinm * Common Development and Distribution License (the "License"). 620c794b3Sgavinm * You may not use this file except in compliance with the License. 720c794b3Sgavinm * 820c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 1020c794b3Sgavinm * See the License for the specific language governing permissions 1120c794b3Sgavinm * and limitations under the License. 1220c794b3Sgavinm * 1320c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 1420c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 1620c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 1720c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 1820c794b3Sgavinm * 1920c794b3Sgavinm * CDDL HEADER END 2020c794b3Sgavinm */ 2120c794b3Sgavinm 2220c794b3Sgavinm /* 23*85738508SVuong Nguyen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2420c794b3Sgavinm * Use is subject to license terms. 2520c794b3Sgavinm */ 2620c794b3Sgavinm 2720c794b3Sgavinm #include <unistd.h> 2820c794b3Sgavinm #include <stdio.h> 2920c794b3Sgavinm #include <stdlib.h> 3020c794b3Sgavinm #include <stdarg.h> 3120c794b3Sgavinm #include <string.h> 3220c794b3Sgavinm #include <strings.h> 3320c794b3Sgavinm #include <limits.h> 3420c794b3Sgavinm #include <alloca.h> 3520c794b3Sgavinm #include <kstat.h> 3620c794b3Sgavinm #include <fcntl.h> 3720c794b3Sgavinm #include <errno.h> 3820c794b3Sgavinm #include <libnvpair.h> 3920c794b3Sgavinm #include <sys/types.h> 4020c794b3Sgavinm #include <sys/bitmap.h> 4120c794b3Sgavinm #include <sys/processor.h> 4220c794b3Sgavinm #include <sys/param.h> 4320c794b3Sgavinm #include <sys/fm/protocol.h> 4420c794b3Sgavinm #include <sys/systeminfo.h> 4520c794b3Sgavinm #include <sys/mc.h> 4620c794b3Sgavinm #include <sys/mc_amd.h> 4720c794b3Sgavinm #include <sys/mc_intel.h> 4820c794b3Sgavinm #include <fm/topo_mod.h> 4920c794b3Sgavinm 5020c794b3Sgavinm #include "chip.h" 5120c794b3Sgavinm 5220c794b3Sgavinm #ifndef MAX 5320c794b3Sgavinm #define MAX(a, b) ((a) > (b) ? (a) : (b)) 5420c794b3Sgavinm #endif 5520c794b3Sgavinm 5620c794b3Sgavinm static const topo_pgroup_info_t dimm_channel_pgroup = 5720c794b3Sgavinm { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5820c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup = 5920c794b3Sgavinm { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6020c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup = 6120c794b3Sgavinm { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6220c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup = 6320c794b3Sgavinm { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6420c794b3Sgavinm 6520c794b3Sgavinm static const topo_method_t dimm_methods[] = { 6620c794b3Sgavinm { SIMPLE_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 6720c794b3Sgavinm simple_dimm_label}, 6820c794b3Sgavinm { SIMPLE_DIMM_LBL_MP, "Property method", 0, TOPO_STABILITY_INTERNAL, 6920c794b3Sgavinm simple_dimm_label_mp}, 7020c794b3Sgavinm { SEQ_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 7120c794b3Sgavinm seq_dimm_label}, 7220c794b3Sgavinm { NULL } 7320c794b3Sgavinm }; 7420c794b3Sgavinm 75e4b86885SCheng Sean Ye extern const topo_method_t rank_methods[]; 76e4b86885SCheng Sean Ye extern const topo_method_t ntv_page_retire_methods[]; 77e4b86885SCheng Sean Ye 7820c794b3Sgavinm static int mc_fd; 7920c794b3Sgavinm 8020c794b3Sgavinm int 8120c794b3Sgavinm mc_offchip_open() 8220c794b3Sgavinm { 8320c794b3Sgavinm mc_fd = open("/dev/mc/mc", O_RDONLY); 8420c794b3Sgavinm return (mc_fd != -1); 8520c794b3Sgavinm } 8620c794b3Sgavinm 87e3d60c9bSAdrian Frost static int 88e3d60c9bSAdrian Frost mc_onchip(topo_instance_t id) 89e3d60c9bSAdrian Frost { 90e3d60c9bSAdrian Frost char path[64]; 91e3d60c9bSAdrian Frost 92e3d60c9bSAdrian Frost (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 93e3d60c9bSAdrian Frost mc_fd = open(path, O_RDONLY); 94e3d60c9bSAdrian Frost return (mc_fd != -1); 95e3d60c9bSAdrian Frost } 96e3d60c9bSAdrian Frost 97*85738508SVuong Nguyen static void 9820c794b3Sgavinm mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm, 99*85738508SVuong Nguyen nvlist_t **ranks_nvp, int start_rank, int nranks, char *serial, char *part, 100*85738508SVuong Nguyen char *rev, int maxranks) 10120c794b3Sgavinm { 10220c794b3Sgavinm int i; 10320c794b3Sgavinm int rank; 10420c794b3Sgavinm tnode_t *rnode; 10520c794b3Sgavinm nvpair_t *nvp; 10620c794b3Sgavinm nvlist_t *fmri; 10720c794b3Sgavinm int err = 0; 10820c794b3Sgavinm 109*85738508SVuong Nguyen /* 110*85738508SVuong Nguyen * If start_rank is defined, it is assigned to the first rank of this 111*85738508SVuong Nguyen * dimm. 112*85738508SVuong Nguyen */ 113*85738508SVuong Nguyen rank = start_rank >= 0 ? start_rank : dimm * maxranks; 11420c794b3Sgavinm if (topo_node_range_create(mod, dnode, RANK, rank, 11520c794b3Sgavinm rank + nranks - 1) < 0) { 116*85738508SVuong Nguyen whinge(mod, NULL, "mc_add_ranks: node range create failed" 11720c794b3Sgavinm " for rank\n"); 11820c794b3Sgavinm return; 11920c794b3Sgavinm } 12020c794b3Sgavinm for (i = 0; i < nranks; i++) { 12120c794b3Sgavinm fmri = topo_mod_hcfmri(mod, dnode, FM_HC_SCHEME_VERSION, 12220c794b3Sgavinm RANK, rank, NULL, auth, part, rev, serial); 12320c794b3Sgavinm if (fmri == NULL) { 12420c794b3Sgavinm whinge(mod, NULL, 12520c794b3Sgavinm "mc_add_ranks: topo_mod_hcfmri failed\n"); 12620c794b3Sgavinm return; 12720c794b3Sgavinm } 12820c794b3Sgavinm if ((rnode = topo_node_bind(mod, dnode, RANK, rank, 12920c794b3Sgavinm fmri)) == NULL) { 13020c794b3Sgavinm nvlist_free(fmri); 13120c794b3Sgavinm whinge(mod, NULL, "mc_add_ranks: node bind failed" 13220c794b3Sgavinm " for ranks\n"); 13320c794b3Sgavinm return; 13420c794b3Sgavinm } 13520c794b3Sgavinm (void) topo_node_fru_set(rnode, NULL, 0, &err); 13620c794b3Sgavinm 13720c794b3Sgavinm if (topo_method_register(mod, rnode, rank_methods) < 0) 13820c794b3Sgavinm whinge(mod, &err, "rank_create: " 13920c794b3Sgavinm "topo_method_register failed"); 14020c794b3Sgavinm 141e4b86885SCheng Sean Ye if (! is_xpv() && topo_method_register(mod, rnode, 142e4b86885SCheng Sean Ye ntv_page_retire_methods) < 0) 143e4b86885SCheng Sean Ye whinge(mod, &err, "mc_add_ranks: " 144e4b86885SCheng Sean Ye "topo_method_register failed"); 145e4b86885SCheng Sean Ye 14620c794b3Sgavinm (void) topo_node_asru_set(rnode, fmri, TOPO_ASRU_COMPUTE, &err); 14720c794b3Sgavinm 14820c794b3Sgavinm nvlist_free(fmri); 14920c794b3Sgavinm 15020c794b3Sgavinm (void) topo_pgroup_create(rnode, &rank_pgroup, &err); 15120c794b3Sgavinm for (nvp = nvlist_next_nvpair(ranks_nvp[i], NULL); nvp != NULL; 15220c794b3Sgavinm nvp = nvlist_next_nvpair(ranks_nvp[i], nvp)) { 15320c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(RANK), rnode); 15420c794b3Sgavinm } 15520c794b3Sgavinm rank++; 15620c794b3Sgavinm } 15720c794b3Sgavinm } 15820c794b3Sgavinm 15920c794b3Sgavinm static void 16020c794b3Sgavinm mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, 161e3d60c9bSAdrian Frost nvlist_t **nvl, uint_t ndimms, int maxranks) 16220c794b3Sgavinm { 16320c794b3Sgavinm int i; 16420c794b3Sgavinm nvlist_t *fmri; 16520c794b3Sgavinm tnode_t *dnode; 16620c794b3Sgavinm nvpair_t *nvp; 16720c794b3Sgavinm int err; 16820c794b3Sgavinm nvlist_t **ranks_nvp; 169*85738508SVuong Nguyen int32_t start_rank = -1; 17020c794b3Sgavinm uint_t nranks = 0; 17120c794b3Sgavinm char *serial = NULL; 17220c794b3Sgavinm char *part = NULL; 17320c794b3Sgavinm char *rev = NULL; 17420c794b3Sgavinm char *label = NULL; 17520c794b3Sgavinm char *name; 17620c794b3Sgavinm 17720c794b3Sgavinm if (topo_node_range_create(mod, pnode, DIMM, 0, ndimms-1) < 0) { 17820c794b3Sgavinm whinge(mod, NULL, 17920c794b3Sgavinm "mc_add_dimms: node range create failed\n"); 18020c794b3Sgavinm return; 18120c794b3Sgavinm } 18220c794b3Sgavinm for (i = 0; i < ndimms; i++) { 18320c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 18420c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 18520c794b3Sgavinm name = nvpair_name(nvp); 18620c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) { 18720c794b3Sgavinm (void) nvpair_value_nvlist_array(nvp, 18820c794b3Sgavinm &ranks_nvp, &nranks); 189*85738508SVuong Nguyen } else if (strcmp(name, MCINTEL_NVLIST_1ST_RANK) == 0) { 190*85738508SVuong Nguyen (void) nvpair_value_int32(nvp, &start_rank); 19120c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) { 19220c794b3Sgavinm (void) nvpair_value_string(nvp, &serial); 19320c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_PART) == 0) { 19420c794b3Sgavinm (void) nvpair_value_string(nvp, &part); 19520c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) { 19620c794b3Sgavinm (void) nvpair_value_string(nvp, &rev); 19720c794b3Sgavinm } else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) { 19820c794b3Sgavinm (void) nvpair_value_string(nvp, &label); 19920c794b3Sgavinm } 20020c794b3Sgavinm } 20120c794b3Sgavinm fmri = NULL; 20220c794b3Sgavinm fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 20320c794b3Sgavinm DIMM, i, NULL, auth, part, rev, serial); 20420c794b3Sgavinm if (fmri == NULL) { 20520c794b3Sgavinm whinge(mod, NULL, 20620c794b3Sgavinm "mc_add_dimms: topo_mod_hcfmri failed\n"); 20720c794b3Sgavinm return; 20820c794b3Sgavinm } 20920c794b3Sgavinm if ((dnode = topo_node_bind(mod, pnode, DIMM, i, 21020c794b3Sgavinm fmri)) == NULL) { 21120c794b3Sgavinm nvlist_free(fmri); 21220c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node bind failed" 21320c794b3Sgavinm " for dimm\n"); 21420c794b3Sgavinm return; 21520c794b3Sgavinm } 21620c794b3Sgavinm 21720c794b3Sgavinm if (topo_method_register(mod, dnode, dimm_methods) < 0) 21820c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: " 21920c794b3Sgavinm "topo_method_register failed"); 22020c794b3Sgavinm 22120c794b3Sgavinm (void) topo_node_fru_set(dnode, fmri, 0, &err); 22220c794b3Sgavinm nvlist_free(fmri); 22320c794b3Sgavinm (void) topo_pgroup_create(dnode, &dimm_pgroup, &err); 22420c794b3Sgavinm 22520c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 22620c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 22720c794b3Sgavinm name = nvpair_name(nvp); 22820c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 && 229*85738508SVuong Nguyen strcmp(name, FM_FAULT_FRU_LABEL) != 0 && 230*85738508SVuong Nguyen strcmp(name, MCINTEL_NVLIST_1ST_RANK) != 0) { 23120c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(DIMM), 23220c794b3Sgavinm dnode); 23320c794b3Sgavinm } 23420c794b3Sgavinm } 23520c794b3Sgavinm if (label) 23620c794b3Sgavinm (void) topo_node_label_set(dnode, label, &err); 23720c794b3Sgavinm 23820c794b3Sgavinm if (nranks) { 239*85738508SVuong Nguyen mc_add_ranks(mod, dnode, auth, i, ranks_nvp, start_rank, 240*85738508SVuong Nguyen nranks, serial, part, rev, maxranks); 24120c794b3Sgavinm } 24220c794b3Sgavinm } 24320c794b3Sgavinm } 24420c794b3Sgavinm 24520c794b3Sgavinm static int 24620c794b3Sgavinm mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth, 247e3d60c9bSAdrian Frost nvlist_t *nvl, int maxranks) 24820c794b3Sgavinm { 24920c794b3Sgavinm tnode_t *mc_channel; 25020c794b3Sgavinm nvlist_t *fmri; 25120c794b3Sgavinm nvlist_t **dimm_nvl; 252e3d60c9bSAdrian Frost nvpair_t *nvp; 253e3d60c9bSAdrian Frost char *name; 25420c794b3Sgavinm uint_t ndimms; 25520c794b3Sgavinm int err; 25620c794b3Sgavinm 25720c794b3Sgavinm if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) { 25820c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n"); 25920c794b3Sgavinm return (-1); 26020c794b3Sgavinm } 26120c794b3Sgavinm if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel, 26220c794b3Sgavinm fmri)) == NULL) { 26320c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n", 26420c794b3Sgavinm DRAMCHANNEL); 26520c794b3Sgavinm nvlist_free(fmri); 26620c794b3Sgavinm return (-1); 26720c794b3Sgavinm } 26820c794b3Sgavinm (void) topo_node_fru_set(mc_channel, NULL, 0, &err); 26920c794b3Sgavinm nvlist_free(fmri); 27020c794b3Sgavinm (void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err); 27120c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl, 27220c794b3Sgavinm &ndimms) == 0) { 273e3d60c9bSAdrian Frost mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms, maxranks); 274e3d60c9bSAdrian Frost } 275e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 276e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 277e3d60c9bSAdrian Frost name = nvpair_name(nvp); 278e3d60c9bSAdrian Frost if (strcmp(name, MCINTEL_NVLIST_DIMMS) != 0) { 279e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(CHAN), 280e3d60c9bSAdrian Frost mc_channel); 281e3d60c9bSAdrian Frost } 28220c794b3Sgavinm } 28320c794b3Sgavinm return (0); 28420c794b3Sgavinm } 28520c794b3Sgavinm 28620c794b3Sgavinm static int 28720c794b3Sgavinm mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 28820c794b3Sgavinm nvlist_t *nvl) 28920c794b3Sgavinm { 29020c794b3Sgavinm int err; 29120c794b3Sgavinm int i, j; 29220c794b3Sgavinm int channel; 293e3d60c9bSAdrian Frost uint8_t nmc; 294e3d60c9bSAdrian Frost uint8_t maxranks; 29520c794b3Sgavinm tnode_t *mcnode; 29620c794b3Sgavinm nvlist_t *fmri; 29720c794b3Sgavinm nvlist_t **channel_nvl; 298e3d60c9bSAdrian Frost nvpair_t *nvp; 299e3d60c9bSAdrian Frost char *pname; 30020c794b3Sgavinm uint_t nchannels; 30120c794b3Sgavinm 30220c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl, 30320c794b3Sgavinm &nchannels) != 0) { 30420c794b3Sgavinm whinge(mod, NULL, 30520c794b3Sgavinm "mc_nb_create: failed to find channel information\n"); 30620c794b3Sgavinm return (-1); 30720c794b3Sgavinm } 308*85738508SVuong Nguyen if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) == 0) { 309*85738508SVuong Nguyen /* 310*85738508SVuong Nguyen * Assume channels are evenly divided among the controllers. 311*85738508SVuong Nguyen * Convert nchannels to channels per controller 312*85738508SVuong Nguyen */ 313*85738508SVuong Nguyen nchannels = nchannels / nmc; 314*85738508SVuong Nguyen } else { 315e3d60c9bSAdrian Frost /* 316e3d60c9bSAdrian Frost * if number of memory controllers is not specified then there 317e3d60c9bSAdrian Frost * are two channels per controller and the nchannels is total 318e3d60c9bSAdrian Frost * we will set up nmc as number of controllers and convert 319e3d60c9bSAdrian Frost * nchannels to channels per controller 320e3d60c9bSAdrian Frost */ 321e3d60c9bSAdrian Frost nmc = nchannels / 2; 322e3d60c9bSAdrian Frost nchannels = nchannels / nmc; 323e3d60c9bSAdrian Frost } 324e3d60c9bSAdrian Frost if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NRANKS, &maxranks) != 0) 325e3d60c9bSAdrian Frost maxranks = 2; 32620c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) { 32720c794b3Sgavinm whinge(mod, NULL, 32820c794b3Sgavinm "mc_nb_create: node range create failed\n"); 32920c794b3Sgavinm return (-1); 33020c794b3Sgavinm } 33120c794b3Sgavinm channel = 0; 33220c794b3Sgavinm for (i = 0; i < nmc; i++) { 33320c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 33420c794b3Sgavinm whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n"); 33520c794b3Sgavinm return (-1); 33620c794b3Sgavinm } 33720c794b3Sgavinm if ((mcnode = topo_node_bind(mod, pnode, name, i, 33820c794b3Sgavinm fmri)) == NULL) { 339e3d60c9bSAdrian Frost whinge(mod, NULL, "mc_nb_create: node bind failed" 34020c794b3Sgavinm " for memory-controller\n"); 34120c794b3Sgavinm nvlist_free(fmri); 34220c794b3Sgavinm return (-1); 34320c794b3Sgavinm } 34420c794b3Sgavinm 34520c794b3Sgavinm (void) topo_node_fru_set(mcnode, NULL, 0, &err); 34620c794b3Sgavinm nvlist_free(fmri); 34720c794b3Sgavinm (void) topo_pgroup_create(mcnode, &mc_pgroup, &err); 34820c794b3Sgavinm 34920c794b3Sgavinm if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel, 350e3d60c9bSAdrian Frost channel + nchannels - 1) < 0) { 35120c794b3Sgavinm whinge(mod, NULL, 35220c794b3Sgavinm "mc_nb_create: channel node range create failed\n"); 35320c794b3Sgavinm return (-1); 35420c794b3Sgavinm } 355e3d60c9bSAdrian Frost for (j = 0; j < nchannels; j++) { 35620c794b3Sgavinm if (mc_add_channel(mod, mcnode, channel, auth, 357e3d60c9bSAdrian Frost channel_nvl[channel], maxranks) < 0) { 35820c794b3Sgavinm return (-1); 35920c794b3Sgavinm } 36020c794b3Sgavinm channel++; 36120c794b3Sgavinm } 362e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 363e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 364e3d60c9bSAdrian Frost pname = nvpair_name(nvp); 365e3d60c9bSAdrian Frost if (strcmp(pname, MCINTEL_NVLIST_MC) != 0 && 366e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NMEM) != 0 && 367e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NRANKS) != 0 && 368e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_VERSTR) != 0 && 369e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_MEM) != 0) { 370e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(MCT), 371e3d60c9bSAdrian Frost mcnode); 372e3d60c9bSAdrian Frost } 373e3d60c9bSAdrian Frost } 37420c794b3Sgavinm } 37520c794b3Sgavinm 37620c794b3Sgavinm return (NULL); 37720c794b3Sgavinm } 37820c794b3Sgavinm 37920c794b3Sgavinm int 380e3d60c9bSAdrian Frost mc_node_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 38120c794b3Sgavinm nvlist_t *auth) 38220c794b3Sgavinm { 38320c794b3Sgavinm mc_snapshot_info_t mcs; 38420c794b3Sgavinm void *buf = NULL; 38520c794b3Sgavinm nvlist_t *nvl; 38620c794b3Sgavinm uint8_t ver; 38720c794b3Sgavinm int rc; 38820c794b3Sgavinm 38920c794b3Sgavinm if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 39020c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 39120c794b3Sgavinm ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) { 39220c794b3Sgavinm 39320c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s\n", 39420c794b3Sgavinm strerror(errno)); 39520c794b3Sgavinm 39620c794b3Sgavinm free(buf); 39720c794b3Sgavinm (void) close(mc_fd); 39820c794b3Sgavinm return (NULL); 39920c794b3Sgavinm } 40020c794b3Sgavinm (void) close(mc_fd); 40120c794b3Sgavinm (void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 40220c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 40320c794b3Sgavinm 40420c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) { 40520c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 40620c794b3Sgavinm nvlist_free(nvl); 40720c794b3Sgavinm return (NULL); 40820c794b3Sgavinm } else if (ver != MCINTEL_NVLIST_VERS0) { 40920c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 41020c794b3Sgavinm nvlist_free(nvl); 41120c794b3Sgavinm return (NULL); 41220c794b3Sgavinm } 41320c794b3Sgavinm 41420c794b3Sgavinm rc = mc_nb_create(mod, pnode, name, auth, nvl); 41520c794b3Sgavinm 41620c794b3Sgavinm nvlist_free(nvl); 41720c794b3Sgavinm return (rc); 41820c794b3Sgavinm } 419e3d60c9bSAdrian Frost 420e3d60c9bSAdrian Frost void 421e3d60c9bSAdrian Frost onchip_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 422e3d60c9bSAdrian Frost nvlist_t *auth) 423e3d60c9bSAdrian Frost { 424e3d60c9bSAdrian Frost if (mc_onchip(topo_node_instance(pnode))) 425e3d60c9bSAdrian Frost (void) mc_node_create(mod, pnode, name, auth); 426e3d60c9bSAdrian Frost } 427e3d60c9bSAdrian Frost 428e3d60c9bSAdrian Frost int 429e3d60c9bSAdrian Frost mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 430e3d60c9bSAdrian Frost nvlist_t *auth) 431e3d60c9bSAdrian Frost { 432e3d60c9bSAdrian Frost return (mc_node_create(mod, pnode, name, auth)); 433e3d60c9bSAdrian Frost } 434