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 /* 2385738508SVuong 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 9785738508SVuong Nguyen static void 9820c794b3Sgavinm mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm, 9985738508SVuong Nguyen nvlist_t **ranks_nvp, int start_rank, int nranks, char *serial, char *part, 10085738508SVuong 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 10985738508SVuong Nguyen /* 11085738508SVuong Nguyen * If start_rank is defined, it is assigned to the first rank of this 11185738508SVuong Nguyen * dimm. 11285738508SVuong Nguyen */ 11385738508SVuong Nguyen rank = start_rank >= 0 ? start_rank : dimm * maxranks; 11420c794b3Sgavinm if (topo_node_range_create(mod, dnode, RANK, rank, 11520c794b3Sgavinm rank + nranks - 1) < 0) { 11685738508SVuong 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, 161*491f61a1SYanmin Sun nvlist_t **nvl, uint_t ndimms, int maxdimms, 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; 16985738508SVuong Nguyen int32_t start_rank = -1; 17020c794b3Sgavinm uint_t nranks = 0; 171*491f61a1SYanmin Sun uint32_t dimm_number; 17220c794b3Sgavinm char *serial = NULL; 17320c794b3Sgavinm char *part = NULL; 17420c794b3Sgavinm char *rev = NULL; 17520c794b3Sgavinm char *label = NULL; 17620c794b3Sgavinm char *name; 17720c794b3Sgavinm 178*491f61a1SYanmin Sun if (topo_node_range_create(mod, pnode, DIMM, 0, 179*491f61a1SYanmin Sun maxdimms ? maxdimms-1 : ndimms-1) < 0) { 18020c794b3Sgavinm whinge(mod, NULL, 18120c794b3Sgavinm "mc_add_dimms: node range create failed\n"); 18220c794b3Sgavinm return; 18320c794b3Sgavinm } 18420c794b3Sgavinm for (i = 0; i < ndimms; i++) { 185*491f61a1SYanmin Sun dimm_number = i; 18620c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 18720c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 18820c794b3Sgavinm name = nvpair_name(nvp); 18920c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) { 19020c794b3Sgavinm (void) nvpair_value_nvlist_array(nvp, 19120c794b3Sgavinm &ranks_nvp, &nranks); 19285738508SVuong Nguyen } else if (strcmp(name, MCINTEL_NVLIST_1ST_RANK) == 0) { 19385738508SVuong Nguyen (void) nvpair_value_int32(nvp, &start_rank); 19420c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) { 19520c794b3Sgavinm (void) nvpair_value_string(nvp, &serial); 19620c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_PART) == 0) { 19720c794b3Sgavinm (void) nvpair_value_string(nvp, &part); 19820c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) { 19920c794b3Sgavinm (void) nvpair_value_string(nvp, &rev); 20020c794b3Sgavinm } else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) { 20120c794b3Sgavinm (void) nvpair_value_string(nvp, &label); 202*491f61a1SYanmin Sun } else if (strcmp(name, MCINTEL_NVLIST_DIMM_NUM) == 0) { 203*491f61a1SYanmin Sun (void) nvpair_value_uint32(nvp, &dimm_number); 20420c794b3Sgavinm } 20520c794b3Sgavinm } 20620c794b3Sgavinm fmri = NULL; 20720c794b3Sgavinm fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 208*491f61a1SYanmin Sun DIMM, dimm_number, NULL, auth, part, rev, serial); 20920c794b3Sgavinm if (fmri == NULL) { 21020c794b3Sgavinm whinge(mod, NULL, 21120c794b3Sgavinm "mc_add_dimms: topo_mod_hcfmri failed\n"); 21220c794b3Sgavinm return; 21320c794b3Sgavinm } 214*491f61a1SYanmin Sun if ((dnode = topo_node_bind(mod, pnode, DIMM, dimm_number, 21520c794b3Sgavinm fmri)) == NULL) { 21620c794b3Sgavinm nvlist_free(fmri); 21720c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node bind failed" 21820c794b3Sgavinm " for dimm\n"); 21920c794b3Sgavinm return; 22020c794b3Sgavinm } 22120c794b3Sgavinm 22220c794b3Sgavinm if (topo_method_register(mod, dnode, dimm_methods) < 0) 22320c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: " 22420c794b3Sgavinm "topo_method_register failed"); 22520c794b3Sgavinm 22620c794b3Sgavinm (void) topo_node_fru_set(dnode, fmri, 0, &err); 22720c794b3Sgavinm nvlist_free(fmri); 22820c794b3Sgavinm (void) topo_pgroup_create(dnode, &dimm_pgroup, &err); 22920c794b3Sgavinm 23020c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 23120c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 23220c794b3Sgavinm name = nvpair_name(nvp); 23320c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 && 23485738508SVuong Nguyen strcmp(name, FM_FAULT_FRU_LABEL) != 0 && 23585738508SVuong Nguyen strcmp(name, MCINTEL_NVLIST_1ST_RANK) != 0) { 23620c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(DIMM), 23720c794b3Sgavinm dnode); 23820c794b3Sgavinm } 23920c794b3Sgavinm } 24020c794b3Sgavinm if (label) 24120c794b3Sgavinm (void) topo_node_label_set(dnode, label, &err); 24220c794b3Sgavinm 24320c794b3Sgavinm if (nranks) { 244*491f61a1SYanmin Sun mc_add_ranks(mod, dnode, auth, dimm_number, ranks_nvp, 245*491f61a1SYanmin Sun start_rank, nranks, serial, part, rev, maxranks); 24620c794b3Sgavinm } 24720c794b3Sgavinm } 24820c794b3Sgavinm } 24920c794b3Sgavinm 25020c794b3Sgavinm static int 25120c794b3Sgavinm mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth, 252*491f61a1SYanmin Sun nvlist_t *nvl, int maxdimms, int maxranks) 25320c794b3Sgavinm { 25420c794b3Sgavinm tnode_t *mc_channel; 25520c794b3Sgavinm nvlist_t *fmri; 25620c794b3Sgavinm nvlist_t **dimm_nvl; 257e3d60c9bSAdrian Frost nvpair_t *nvp; 258e3d60c9bSAdrian Frost char *name; 25920c794b3Sgavinm uint_t ndimms; 26020c794b3Sgavinm int err; 26120c794b3Sgavinm 26220c794b3Sgavinm if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) { 26320c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n"); 26420c794b3Sgavinm return (-1); 26520c794b3Sgavinm } 26620c794b3Sgavinm if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel, 26720c794b3Sgavinm fmri)) == NULL) { 26820c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n", 26920c794b3Sgavinm DRAMCHANNEL); 27020c794b3Sgavinm nvlist_free(fmri); 27120c794b3Sgavinm return (-1); 27220c794b3Sgavinm } 27320c794b3Sgavinm (void) topo_node_fru_set(mc_channel, NULL, 0, &err); 27420c794b3Sgavinm nvlist_free(fmri); 27520c794b3Sgavinm (void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err); 27620c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl, 27720c794b3Sgavinm &ndimms) == 0) { 278*491f61a1SYanmin Sun mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms, maxdimms, 279*491f61a1SYanmin Sun maxranks); 280e3d60c9bSAdrian Frost } 281e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 282e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 283e3d60c9bSAdrian Frost name = nvpair_name(nvp); 284e3d60c9bSAdrian Frost if (strcmp(name, MCINTEL_NVLIST_DIMMS) != 0) { 285e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(CHAN), 286e3d60c9bSAdrian Frost mc_channel); 287e3d60c9bSAdrian Frost } 28820c794b3Sgavinm } 28920c794b3Sgavinm return (0); 29020c794b3Sgavinm } 29120c794b3Sgavinm 29220c794b3Sgavinm static int 29320c794b3Sgavinm mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 29420c794b3Sgavinm nvlist_t *nvl) 29520c794b3Sgavinm { 29620c794b3Sgavinm int err; 29720c794b3Sgavinm int i, j; 29820c794b3Sgavinm int channel; 299e3d60c9bSAdrian Frost uint8_t nmc; 300e3d60c9bSAdrian Frost uint8_t maxranks; 301*491f61a1SYanmin Sun uint8_t maxdimms; 30220c794b3Sgavinm tnode_t *mcnode; 30320c794b3Sgavinm nvlist_t *fmri; 30420c794b3Sgavinm nvlist_t **channel_nvl; 305e3d60c9bSAdrian Frost nvpair_t *nvp; 306e3d60c9bSAdrian Frost char *pname; 30720c794b3Sgavinm uint_t nchannels; 30820c794b3Sgavinm 30920c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl, 31020c794b3Sgavinm &nchannels) != 0) { 31120c794b3Sgavinm whinge(mod, NULL, 31220c794b3Sgavinm "mc_nb_create: failed to find channel information\n"); 31320c794b3Sgavinm return (-1); 31420c794b3Sgavinm } 31585738508SVuong Nguyen if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) == 0) { 31685738508SVuong Nguyen /* 31785738508SVuong Nguyen * Assume channels are evenly divided among the controllers. 31885738508SVuong Nguyen * Convert nchannels to channels per controller 31985738508SVuong Nguyen */ 32085738508SVuong Nguyen nchannels = nchannels / nmc; 32185738508SVuong Nguyen } else { 322e3d60c9bSAdrian Frost /* 323e3d60c9bSAdrian Frost * if number of memory controllers is not specified then there 324e3d60c9bSAdrian Frost * are two channels per controller and the nchannels is total 325e3d60c9bSAdrian Frost * we will set up nmc as number of controllers and convert 326e3d60c9bSAdrian Frost * nchannels to channels per controller 327e3d60c9bSAdrian Frost */ 328e3d60c9bSAdrian Frost nmc = nchannels / 2; 329e3d60c9bSAdrian Frost nchannels = nchannels / nmc; 330e3d60c9bSAdrian Frost } 331e3d60c9bSAdrian Frost if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NRANKS, &maxranks) != 0) 332e3d60c9bSAdrian Frost maxranks = 2; 333*491f61a1SYanmin Sun if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NDIMMS, &maxdimms) != 0) 334*491f61a1SYanmin Sun maxdimms = 0; 33520c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) { 33620c794b3Sgavinm whinge(mod, NULL, 33720c794b3Sgavinm "mc_nb_create: node range create failed\n"); 33820c794b3Sgavinm return (-1); 33920c794b3Sgavinm } 34020c794b3Sgavinm channel = 0; 34120c794b3Sgavinm for (i = 0; i < nmc; i++) { 34220c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 34320c794b3Sgavinm whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n"); 34420c794b3Sgavinm return (-1); 34520c794b3Sgavinm } 34620c794b3Sgavinm if ((mcnode = topo_node_bind(mod, pnode, name, i, 34720c794b3Sgavinm fmri)) == NULL) { 348e3d60c9bSAdrian Frost whinge(mod, NULL, "mc_nb_create: node bind failed" 34920c794b3Sgavinm " for memory-controller\n"); 35020c794b3Sgavinm nvlist_free(fmri); 35120c794b3Sgavinm return (-1); 35220c794b3Sgavinm } 35320c794b3Sgavinm 35420c794b3Sgavinm (void) topo_node_fru_set(mcnode, NULL, 0, &err); 35520c794b3Sgavinm nvlist_free(fmri); 35620c794b3Sgavinm (void) topo_pgroup_create(mcnode, &mc_pgroup, &err); 35720c794b3Sgavinm 35820c794b3Sgavinm if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel, 359e3d60c9bSAdrian Frost channel + nchannels - 1) < 0) { 36020c794b3Sgavinm whinge(mod, NULL, 36120c794b3Sgavinm "mc_nb_create: channel node range create failed\n"); 36220c794b3Sgavinm return (-1); 36320c794b3Sgavinm } 364e3d60c9bSAdrian Frost for (j = 0; j < nchannels; j++) { 36520c794b3Sgavinm if (mc_add_channel(mod, mcnode, channel, auth, 366*491f61a1SYanmin Sun channel_nvl[channel], maxdimms, maxranks) < 0) { 36720c794b3Sgavinm return (-1); 36820c794b3Sgavinm } 36920c794b3Sgavinm channel++; 37020c794b3Sgavinm } 371e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 372e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 373e3d60c9bSAdrian Frost pname = nvpair_name(nvp); 374e3d60c9bSAdrian Frost if (strcmp(pname, MCINTEL_NVLIST_MC) != 0 && 375e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NMEM) != 0 && 376e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NRANKS) != 0 && 377*491f61a1SYanmin Sun strcmp(pname, MCINTEL_NVLIST_NDIMMS) != 0 && 378e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_VERSTR) != 0 && 379e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_MEM) != 0) { 380e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(MCT), 381e3d60c9bSAdrian Frost mcnode); 382e3d60c9bSAdrian Frost } 383e3d60c9bSAdrian Frost } 38420c794b3Sgavinm } 38520c794b3Sgavinm 38620c794b3Sgavinm return (NULL); 38720c794b3Sgavinm } 38820c794b3Sgavinm 38920c794b3Sgavinm int 390e3d60c9bSAdrian Frost mc_node_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 39120c794b3Sgavinm nvlist_t *auth) 39220c794b3Sgavinm { 39320c794b3Sgavinm mc_snapshot_info_t mcs; 39420c794b3Sgavinm void *buf = NULL; 39520c794b3Sgavinm nvlist_t *nvl; 39620c794b3Sgavinm uint8_t ver; 39720c794b3Sgavinm int rc; 39820c794b3Sgavinm 39920c794b3Sgavinm if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 40020c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 40120c794b3Sgavinm ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) { 40220c794b3Sgavinm 40320c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s\n", 40420c794b3Sgavinm strerror(errno)); 40520c794b3Sgavinm 40620c794b3Sgavinm free(buf); 40720c794b3Sgavinm (void) close(mc_fd); 40820c794b3Sgavinm return (NULL); 40920c794b3Sgavinm } 41020c794b3Sgavinm (void) close(mc_fd); 41120c794b3Sgavinm (void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 41220c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 41320c794b3Sgavinm 41420c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) { 41520c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 41620c794b3Sgavinm nvlist_free(nvl); 41720c794b3Sgavinm return (NULL); 41820c794b3Sgavinm } else if (ver != MCINTEL_NVLIST_VERS0) { 41920c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 42020c794b3Sgavinm nvlist_free(nvl); 42120c794b3Sgavinm return (NULL); 42220c794b3Sgavinm } 42320c794b3Sgavinm 42420c794b3Sgavinm rc = mc_nb_create(mod, pnode, name, auth, nvl); 42520c794b3Sgavinm 42620c794b3Sgavinm nvlist_free(nvl); 42720c794b3Sgavinm return (rc); 42820c794b3Sgavinm } 429e3d60c9bSAdrian Frost 430e3d60c9bSAdrian Frost void 431e3d60c9bSAdrian Frost onchip_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 432e3d60c9bSAdrian Frost nvlist_t *auth) 433e3d60c9bSAdrian Frost { 434e3d60c9bSAdrian Frost if (mc_onchip(topo_node_instance(pnode))) 435e3d60c9bSAdrian Frost (void) mc_node_create(mod, pnode, name, auth); 436e3d60c9bSAdrian Frost } 437e3d60c9bSAdrian Frost 438e3d60c9bSAdrian Frost int 439e3d60c9bSAdrian Frost mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 440e3d60c9bSAdrian Frost nvlist_t *auth) 441e3d60c9bSAdrian Frost { 442e3d60c9bSAdrian Frost return (mc_node_create(mod, pnode, name, auth)); 443e3d60c9bSAdrian Frost } 444