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*efd31e1dSTrang Do * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2420c794b3Sgavinm */ 2520c794b3Sgavinm 2620c794b3Sgavinm /* 2720c794b3Sgavinm * AMD memory enumeration 2820c794b3Sgavinm */ 2920c794b3Sgavinm 3020c794b3Sgavinm #include <sys/types.h> 3120c794b3Sgavinm #include <unistd.h> 3220c794b3Sgavinm #include <stropts.h> 3320c794b3Sgavinm #include <sys/fm/protocol.h> 3420c794b3Sgavinm #include <sys/mc.h> 3520c794b3Sgavinm #include <sys/mc_amd.h> 3620c794b3Sgavinm #include <fm/topo_mod.h> 3720c794b3Sgavinm #include <strings.h> 3820c794b3Sgavinm #include <sys/stat.h> 3920c794b3Sgavinm #include <fcntl.h> 4020c794b3Sgavinm 4120c794b3Sgavinm #include "chip.h" 4220c794b3Sgavinm 4320c794b3Sgavinm #define MAX_CHANNUM 1 4420c794b3Sgavinm #define MAX_DIMMNUM 7 4520c794b3Sgavinm #define MAX_CSNUM 7 4620c794b3Sgavinm 4720c794b3Sgavinm static const topo_pgroup_info_t cs_pgroup = 4820c794b3Sgavinm { PGNAME(CS), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 4920c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup = 5020c794b3Sgavinm { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5120c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup = 5220c794b3Sgavinm { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5320c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup = 5420c794b3Sgavinm { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5520c794b3Sgavinm static const topo_pgroup_info_t chan_pgroup = 5620c794b3Sgavinm { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5720c794b3Sgavinm 5820c794b3Sgavinm static const topo_method_t dimm_methods[] = { 5920c794b3Sgavinm { SIMPLE_DIMM_LBL, "Property method", 0, 6020c794b3Sgavinm TOPO_STABILITY_INTERNAL, simple_dimm_label}, 6120c794b3Sgavinm { SIMPLE_DIMM_LBL_MP, "Property method", 0, 6220c794b3Sgavinm TOPO_STABILITY_INTERNAL, simple_dimm_label_mp}, 6320c794b3Sgavinm { SEQ_DIMM_LBL, "Property method", 0, 6420c794b3Sgavinm TOPO_STABILITY_INTERNAL, seq_dimm_label}, 652cb5535aSrobj { G4_DIMM_LBL, "Property method", 0, 662cb5535aSrobj TOPO_STABILITY_INTERNAL, g4_dimm_label}, 67918a0d8aSrobj { G12F_DIMM_LBL, "Property method", 0, 68918a0d8aSrobj TOPO_STABILITY_INTERNAL, g12f_dimm_label}, 692cb5535aSrobj { GET_DIMM_SERIAL, "Property method", 0, 702cb5535aSrobj TOPO_STABILITY_INTERNAL, get_dimm_serial}, 7120c794b3Sgavinm { NULL } 7220c794b3Sgavinm }; 7320c794b3Sgavinm 74e4b86885SCheng Sean Ye const topo_method_t rank_methods[] = { 7520c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 7620c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 7720c794b3Sgavinm mem_asru_compute }, 782cb5535aSrobj { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, 792cb5535aSrobj TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, 802cb5535aSrobj rank_fmri_present }, 8125c6ff4bSstephh { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, 8225c6ff4bSstephh TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, 8325c6ff4bSstephh rank_fmri_replaced }, 8420c794b3Sgavinm { NULL } 8520c794b3Sgavinm }; 8620c794b3Sgavinm 87e4b86885SCheng Sean Ye const topo_method_t ntv_page_retire_methods[] = { 88e4b86885SCheng Sean Ye { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC, 89e4b86885SCheng Sean Ye TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL, 90e4b86885SCheng Sean Ye ntv_page_retire }, 91e4b86885SCheng Sean Ye { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC, 92e4b86885SCheng Sean Ye TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL, 93e4b86885SCheng Sean Ye ntv_page_unretire }, 94e4b86885SCheng Sean Ye { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, 95e4b86885SCheng Sean Ye TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, 96e4b86885SCheng Sean Ye ntv_page_service_state }, 97e4b86885SCheng Sean Ye { NULL } 98e4b86885SCheng Sean Ye }; 99e4b86885SCheng Sean Ye 100074bb90dSTom Pothier /* 101074bb90dSTom Pothier * Serials, Labels are obtained from SMBIOS, so 102074bb90dSTom Pothier * we leave out the related methods, any other 103074bb90dSTom Pothier * methods that will be added to gen_cs_methods 104074bb90dSTom Pothier * should be added to x86pi_gen_cs_methods too 105074bb90dSTom Pothier */ 106074bb90dSTom Pothier static const topo_method_t x86pi_gen_cs_methods[] = { 107074bb90dSTom Pothier { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 108074bb90dSTom Pothier TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 109074bb90dSTom Pothier mem_asru_compute }, 110074bb90dSTom Pothier { NULL } 111074bb90dSTom Pothier }; 112074bb90dSTom Pothier 11320c794b3Sgavinm static const topo_method_t gen_cs_methods[] = { 11420c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 11520c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 11620c794b3Sgavinm mem_asru_compute }, 1175108f83cSrobj { SIMPLE_CS_LBL_MP, "Property method", 0, 1185108f83cSrobj TOPO_STABILITY_INTERNAL, simple_cs_label_mp}, 11988045cffSRobert Johnston { GET_DIMM_SERIAL, "Property method", 0, 12088045cffSRobert Johnston TOPO_STABILITY_INTERNAL, get_dimm_serial}, 12120c794b3Sgavinm { NULL } 12220c794b3Sgavinm }; 12320c794b3Sgavinm 12420c794b3Sgavinm static nvlist_t *cs_fmri[MC_CHIP_NCS]; 12520c794b3Sgavinm 12620c794b3Sgavinm /* 12720c794b3Sgavinm * Called when there is no memory-controller driver to provide topology 12820c794b3Sgavinm * information. Generate a maximal memory topology that is appropriate 12920c794b3Sgavinm * for the chip revision. The memory-controller node has already been 13020c794b3Sgavinm * bound as mcnode, and the parent of that is cnode. 13120c794b3Sgavinm * 13220c794b3Sgavinm * We create a tree of dram-channel and chip-select nodes below the 13320c794b3Sgavinm * memory-controller node. There will be two dram channels and 8 chip-selects 13420c794b3Sgavinm * below each, regardless of actual socket type, processor revision and so on. 1358031591dSSrihari Venkatesan * This is adequate for generic diagnosis up to family 0x10 revision D. 13620c794b3Sgavinm */ 13720c794b3Sgavinm /*ARGSUSED*/ 13820c794b3Sgavinm static int 139074bb90dSTom Pothier amd_generic_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *cnode, 1408031591dSSrihari Venkatesan tnode_t *mcnode, int family, int model, nvlist_t *auth) 14120c794b3Sgavinm { 14220c794b3Sgavinm int chan, cs; 14320c794b3Sgavinm 14420c794b3Sgavinm /* 14520c794b3Sgavinm * Elsewhere we have already returned for families less than 0xf. 14620c794b3Sgavinm * This "generic" topology is adequate for all of family 0xf and 1478031591dSSrihari Venkatesan * for revisions A to D of family 0x10 (for the list of models 148b8201470SSrihari Venkatesan * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c). 1498031591dSSrihari Venkatesan * We cover all family 0x10 models, till model 9. 15020c794b3Sgavinm */ 1518031591dSSrihari Venkatesan if (family > 0x10 || (family == 0x10 && model > 9)) 15220c794b3Sgavinm return (1); 15320c794b3Sgavinm 15420c794b3Sgavinm if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0, 15520c794b3Sgavinm MAX_CHANNUM) < 0) { 15620c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: range create for " 15720c794b3Sgavinm "channels failed\n"); 15820c794b3Sgavinm return (-1); 15920c794b3Sgavinm } 16020c794b3Sgavinm 16120c794b3Sgavinm for (chan = 0; chan <= MAX_CHANNUM; chan++) { 16220c794b3Sgavinm tnode_t *chnode; 16320c794b3Sgavinm nvlist_t *fmri; 16420c794b3Sgavinm int err; 16520c794b3Sgavinm 16620c794b3Sgavinm if (mkrsrc(mod, mcnode, CHAN_NODE_NAME, chan, auth, 16720c794b3Sgavinm &fmri) != 0) { 16820c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: mkrsrc " 16920c794b3Sgavinm "failed\n"); 17020c794b3Sgavinm return (-1); 17120c794b3Sgavinm } 17220c794b3Sgavinm 17320c794b3Sgavinm if ((chnode = topo_node_bind(mod, mcnode, CHAN_NODE_NAME, 17420c794b3Sgavinm chan, fmri)) == NULL) { 17520c794b3Sgavinm nvlist_free(fmri); 17620c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: node " 17720c794b3Sgavinm "bind failed\n"); 17820c794b3Sgavinm return (-1); 17920c794b3Sgavinm } 18020c794b3Sgavinm 18120c794b3Sgavinm nvlist_free(fmri); 18220c794b3Sgavinm 18320c794b3Sgavinm (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 18420c794b3Sgavinm 18520c794b3Sgavinm (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 18620c794b3Sgavinm TOPO_PROP_IMMUTABLE, chan == 0 ? "A" : "B", &err); 18720c794b3Sgavinm 188074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 189074bb90dSTom Pothier if (topo_node_label_set(chnode, NULL, &err) == -1) 190074bb90dSTom Pothier whinge(mod, NULL, "amd_generic_mc_create: " 191074bb90dSTom Pothier "topo_node_label_set\n"); 192074bb90dSTom Pothier if (topo_node_fru_set(chnode, NULL, 0, &err) != 0) 193074bb90dSTom Pothier whinge(mod, NULL, "amd_generic_mc_create: " 194074bb90dSTom Pothier "topo_node_fru_set failed\n"); 195074bb90dSTom Pothier } 196074bb90dSTom Pothier 19720c794b3Sgavinm if (topo_node_range_create(mod, chnode, CS_NODE_NAME, 19820c794b3Sgavinm 0, MAX_CSNUM) < 0) { 19920c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 20020c794b3Sgavinm "range create for cs failed\n"); 20120c794b3Sgavinm return (-1); 20220c794b3Sgavinm } 20320c794b3Sgavinm 20420c794b3Sgavinm for (cs = 0; cs <= MAX_CSNUM; cs++) { 20520c794b3Sgavinm tnode_t *csnode; 20620c794b3Sgavinm 20720c794b3Sgavinm if (mkrsrc(mod, chnode, CS_NODE_NAME, cs, auth, 20820c794b3Sgavinm &fmri) != 0) { 20920c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 21020c794b3Sgavinm "mkrsrc for cs failed\n"); 21120c794b3Sgavinm return (-1); 21220c794b3Sgavinm } 21320c794b3Sgavinm 21420c794b3Sgavinm if ((csnode = topo_node_bind(mod, chnode, CS_NODE_NAME, 21520c794b3Sgavinm cs, fmri)) == NULL) { 21620c794b3Sgavinm nvlist_free(fmri); 21720c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 21820c794b3Sgavinm "bind for cs failed\n"); 21920c794b3Sgavinm return (-1); 22020c794b3Sgavinm } 22120c794b3Sgavinm 22220c794b3Sgavinm /* 22320c794b3Sgavinm * Dynamic ASRU for page faults within a chip-select. 22420c794b3Sgavinm * The topology does not represent pages (there are 22520c794b3Sgavinm * too many) so when a page is faulted we generate 22620c794b3Sgavinm * an ASRU to represent the individual page. 227074bb90dSTom Pothier * If SMBIOS meets FMA needs, derive labels & serials 228074bb90dSTom Pothier * for DIMMS and apply to chip-select nodes. 229074bb90dSTom Pothier * If deriving from SMBIOS, skip IPMI 23020c794b3Sgavinm */ 231074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 232074bb90dSTom Pothier if (topo_method_register(mod, csnode, 233074bb90dSTom Pothier x86pi_gen_cs_methods) < 0) 234074bb90dSTom Pothier whinge(mod, NULL, 235074bb90dSTom Pothier "amd_generic_mc_create: " 236074bb90dSTom Pothier "method registration failed\n"); 237074bb90dSTom Pothier } else { 238074bb90dSTom Pothier if (topo_method_register(mod, csnode, 239074bb90dSTom Pothier gen_cs_methods) < 0) 240074bb90dSTom Pothier whinge(mod, NULL, 241074bb90dSTom Pothier "amd_generic_mc_create: method" 242074bb90dSTom Pothier "registration failed\n"); 243074bb90dSTom Pothier } 24420c794b3Sgavinm 24520c794b3Sgavinm (void) topo_node_asru_set(csnode, fmri, 24620c794b3Sgavinm TOPO_ASRU_COMPUTE, &err); 24720c794b3Sgavinm nvlist_free(fmri); 248074bb90dSTom Pothier 249074bb90dSTom Pothier /* 250074bb90dSTom Pothier * If SMBIOS meets FMA needs, set DIMM as the FRU for 251074bb90dSTom Pothier * the chip-select node. Use the channel & chip-select 252074bb90dSTom Pothier * numbers to get the DIMM instance. 253074bb90dSTom Pothier * Send via inst : dram channel number 254074bb90dSTom Pothier * Receive via inst : dimm instance 255074bb90dSTom Pothier */ 256074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 257074bb90dSTom Pothier int inst; 258074bb90dSTom Pothier id_t dimm_smbid; 259074bb90dSTom Pothier const char *serial; 260074bb90dSTom Pothier const char *part; 261074bb90dSTom Pothier const char *rev; 262074bb90dSTom Pothier char *label; 263074bb90dSTom Pothier 264074bb90dSTom Pothier (void) topo_pgroup_create(csnode, 265074bb90dSTom Pothier &cs_pgroup, &err); 266074bb90dSTom Pothier inst = chan; 267*efd31e1dSTrang Do dimm_smbid = memnode_to_smbiosid(mod, smbid, 268074bb90dSTom Pothier CS_NODE_NAME, cs, &inst); 269074bb90dSTom Pothier serial = chip_serial_smbios_get(mod, 270074bb90dSTom Pothier dimm_smbid); 271074bb90dSTom Pothier part = chip_part_smbios_get(mod, 272074bb90dSTom Pothier dimm_smbid); 273074bb90dSTom Pothier rev = chip_rev_smbios_get(mod, dimm_smbid); 274074bb90dSTom Pothier label = (char *)chip_label_smbios_get(mod, 275074bb90dSTom Pothier chnode, dimm_smbid, NULL); 276074bb90dSTom Pothier 277074bb90dSTom Pothier (void) topo_prop_set_string(csnode, PGNAME(CS), 278074bb90dSTom Pothier FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, 279074bb90dSTom Pothier serial, &err); 280074bb90dSTom Pothier (void) topo_prop_set_string(csnode, PGNAME(CS), 281074bb90dSTom Pothier FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, 282074bb90dSTom Pothier part, &err); 283074bb90dSTom Pothier (void) topo_prop_set_string(csnode, PGNAME(CS), 284074bb90dSTom Pothier FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, 285074bb90dSTom Pothier rev, &err); 286074bb90dSTom Pothier 287074bb90dSTom Pothier /* 288074bb90dSTom Pothier * We apply DIMM labels to chip-select nodes, 289074bb90dSTom Pothier * FRU for chip-selects should be DIMMs, and 290074bb90dSTom Pothier * we do not derive dimm nodes for Family 0x10 291074bb90dSTom Pothier * so FRU fmri is NULL, but FRU Labels are set, 292074bb90dSTom Pothier * the FRU labels point to the DIMM. 293074bb90dSTom Pothier */ 294074bb90dSTom Pothier (void) topo_node_label_set(csnode, label, &err); 295074bb90dSTom Pothier topo_mod_strfree(mod, label); 296074bb90dSTom Pothier } 29720c794b3Sgavinm } 29820c794b3Sgavinm } 29920c794b3Sgavinm 30020c794b3Sgavinm return (0); 30120c794b3Sgavinm } 30220c794b3Sgavinm 30320c794b3Sgavinm static nvlist_t * 30420c794b3Sgavinm amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) 30520c794b3Sgavinm { 30620c794b3Sgavinm mc_snapshot_info_t mcs; 30720c794b3Sgavinm void *buf = NULL; 30820c794b3Sgavinm uint8_t ver; 30920c794b3Sgavinm 31020c794b3Sgavinm nvlist_t *nvl = NULL; 31120c794b3Sgavinm char path[64]; 31220c794b3Sgavinm int fd, err; 31320c794b3Sgavinm 31420c794b3Sgavinm (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 31520c794b3Sgavinm fd = open(path, O_RDONLY); 31620c794b3Sgavinm 31720c794b3Sgavinm if (fd == -1) { 31820c794b3Sgavinm /* 31920c794b3Sgavinm * Some v20z and v40z systems may have had the 3rd-party 32020c794b3Sgavinm * NWSnps packagae installed which installs a /dev/mc 32120c794b3Sgavinm * link. So try again via /devices. 32220c794b3Sgavinm */ 32320c794b3Sgavinm (void) snprintf(path, sizeof (path), 32420c794b3Sgavinm "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd", 32520c794b3Sgavinm MC_AMD_DEV_OFFSET + id); 32620c794b3Sgavinm fd = open(path, O_RDONLY); 32720c794b3Sgavinm } 32820c794b3Sgavinm 32920c794b3Sgavinm if (fd == -1) 33020c794b3Sgavinm return (NULL); /* do not whinge */ 33120c794b3Sgavinm 33220c794b3Sgavinm if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 33320c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 33420c794b3Sgavinm ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { 33520c794b3Sgavinm 33620c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s: %s\n", 33720c794b3Sgavinm path, strerror(errno)); 33820c794b3Sgavinm 33920c794b3Sgavinm free(buf); 34020c794b3Sgavinm (void) close(fd); 34120c794b3Sgavinm return (NULL); 34220c794b3Sgavinm } 34320c794b3Sgavinm 34420c794b3Sgavinm (void) close(fd); 34520c794b3Sgavinm err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 34620c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 34720c794b3Sgavinm 34820c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) { 34920c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 35020c794b3Sgavinm nvlist_free(nvl); 35120c794b3Sgavinm return (NULL); 35220c794b3Sgavinm } else if (ver != MC_NVLIST_VERS1) { 35320c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 35420c794b3Sgavinm nvlist_free(nvl); 35520c794b3Sgavinm return (NULL); 35620c794b3Sgavinm } 35720c794b3Sgavinm 35820c794b3Sgavinm return (err ? NULL : nvl); 35920c794b3Sgavinm } 36020c794b3Sgavinm 36120c794b3Sgavinm int 36220c794b3Sgavinm amd_rank_create(topo_mod_t *mod, tnode_t *pnode, nvlist_t *dimmnvl, 36320c794b3Sgavinm nvlist_t *auth) 36420c794b3Sgavinm { 36520c794b3Sgavinm uint64_t *csnumarr; 36620c794b3Sgavinm char **csnamearr; 36720c794b3Sgavinm uint_t ncs, ncsname; 36820c794b3Sgavinm tnode_t *ranknode; 36920c794b3Sgavinm nvlist_t *fmri, *pfmri = NULL; 37020c794b3Sgavinm uint64_t dsz, rsz; 37120c794b3Sgavinm int nerr = 0; 37220c794b3Sgavinm int err; 37320c794b3Sgavinm int i; 37420c794b3Sgavinm 37520c794b3Sgavinm if (nvlist_lookup_uint64_array(dimmnvl, "csnums", &csnumarr, 37620c794b3Sgavinm &ncs) != 0 || nvlist_lookup_string_array(dimmnvl, "csnames", 37720c794b3Sgavinm &csnamearr, &ncsname) != 0 || ncs != ncsname) { 37820c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: " 37920c794b3Sgavinm "csnums/csnames extraction failed\n"); 38020c794b3Sgavinm return (nerr); 38120c794b3Sgavinm } 38220c794b3Sgavinm 38320c794b3Sgavinm if (topo_node_resource(pnode, &pfmri, &err) < 0) { 38420c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: parent fmri lookup " 38520c794b3Sgavinm "failed\n"); 38620c794b3Sgavinm return (nerr); 38720c794b3Sgavinm } 38820c794b3Sgavinm 38920c794b3Sgavinm if (topo_node_range_create(mod, pnode, RANK_NODE_NAME, 0, ncs) < 0) { 39020c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: range create failed\n"); 39120c794b3Sgavinm nvlist_free(pfmri); 39220c794b3Sgavinm return (nerr); 39320c794b3Sgavinm } 39420c794b3Sgavinm 39520c794b3Sgavinm if (topo_prop_get_uint64(pnode, PGNAME(DIMM), "size", &dsz, 39620c794b3Sgavinm &err) == 0) { 39720c794b3Sgavinm rsz = dsz / ncs; 39820c794b3Sgavinm } else { 39920c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: parent dimm has no " 40020c794b3Sgavinm "size\n"); 40120c794b3Sgavinm return (nerr); 40220c794b3Sgavinm } 40320c794b3Sgavinm 40420c794b3Sgavinm for (i = 0; i < ncs; i++) { 40520c794b3Sgavinm if (mkrsrc(mod, pnode, RANK_NODE_NAME, i, auth, &fmri) < 0) { 40620c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: mkrsrc failed\n"); 40720c794b3Sgavinm continue; 40820c794b3Sgavinm } 40920c794b3Sgavinm 41020c794b3Sgavinm if ((ranknode = topo_node_bind(mod, pnode, RANK_NODE_NAME, i, 41120c794b3Sgavinm fmri)) == NULL) { 41220c794b3Sgavinm nvlist_free(fmri); 41320c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: node bind " 41420c794b3Sgavinm "failed\n"); 41520c794b3Sgavinm continue; 41620c794b3Sgavinm } 41720c794b3Sgavinm 41820c794b3Sgavinm nvlist_free(fmri); 419074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) 420074bb90dSTom Pothier (void) topo_node_fru_set(ranknode, NULL, 0, &err); 421074bb90dSTom Pothier else 422074bb90dSTom Pothier (void) topo_node_fru_set(ranknode, pfmri, 0, &err); 42320c794b3Sgavinm 42420c794b3Sgavinm /* 42520c794b3Sgavinm * If a rank is faulted the asru is the associated 42620c794b3Sgavinm * chip-select, but if a page within a rank is faulted 42720c794b3Sgavinm * the asru is just that page. Hence the dual preconstructed 42820c794b3Sgavinm * and computed ASRU. 42920c794b3Sgavinm */ 43020c794b3Sgavinm if (topo_method_register(mod, ranknode, rank_methods) < 0) 43120c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: " 43220c794b3Sgavinm "topo_method_register failed"); 43320c794b3Sgavinm 434e4b86885SCheng Sean Ye if (! is_xpv() && topo_method_register(mod, ranknode, 435e4b86885SCheng Sean Ye ntv_page_retire_methods) < 0) 436e4b86885SCheng Sean Ye whinge(mod, &nerr, "amd_rank_create: " 437e4b86885SCheng Sean Ye "topo_method_register failed"); 438e4b86885SCheng Sean Ye 43920c794b3Sgavinm (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]], 44020c794b3Sgavinm TOPO_ASRU_COMPUTE, &err); 44120c794b3Sgavinm 44220c794b3Sgavinm (void) topo_pgroup_create(ranknode, &rank_pgroup, &err); 44320c794b3Sgavinm 44420c794b3Sgavinm (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size", 44520c794b3Sgavinm TOPO_PROP_IMMUTABLE, rsz, &err); 44620c794b3Sgavinm 44720c794b3Sgavinm (void) topo_prop_set_string(ranknode, PGNAME(RANK), "csname", 44820c794b3Sgavinm TOPO_PROP_IMMUTABLE, csnamearr[i], &err); 44920c794b3Sgavinm 45020c794b3Sgavinm (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "csnum", 45120c794b3Sgavinm TOPO_PROP_IMMUTABLE, csnumarr[i], &err); 45220c794b3Sgavinm } 45320c794b3Sgavinm 45420c794b3Sgavinm nvlist_free(pfmri); 45520c794b3Sgavinm 45620c794b3Sgavinm return (nerr); 45720c794b3Sgavinm } 45820c794b3Sgavinm 45920c794b3Sgavinm static int 460074bb90dSTom Pothier amd_dimm_create(topo_mod_t *mod, uint16_t chip_smbid, tnode_t *pnode, 461074bb90dSTom Pothier const char *name, nvlist_t *mc, nvlist_t *auth) 46220c794b3Sgavinm { 46320c794b3Sgavinm int i, err, nerr = 0; 464074bb90dSTom Pothier int perr = 0; 46520c794b3Sgavinm nvpair_t *nvp; 46620c794b3Sgavinm tnode_t *dimmnode; 467e4b86885SCheng Sean Ye nvlist_t *fmri, **dimmarr = NULL; 46820c794b3Sgavinm uint64_t num; 46920c794b3Sgavinm uint_t ndimm; 470074bb90dSTom Pothier id_t smbid; 471074bb90dSTom Pothier const char *serial; 472074bb90dSTom Pothier const char *part; 473074bb90dSTom Pothier const char *rev; 47420c794b3Sgavinm 47520c794b3Sgavinm if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) { 47620c794b3Sgavinm whinge(mod, NULL, "amd_dimm_create: dimmlist lookup failed\n"); 47720c794b3Sgavinm return (-1); 47820c794b3Sgavinm } 47920c794b3Sgavinm 48020c794b3Sgavinm if (ndimm == 0) 48120c794b3Sgavinm return (0); /* no dimms present on this node */ 48220c794b3Sgavinm 48320c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, MAX_DIMMNUM) < 0) { 48420c794b3Sgavinm whinge(mod, NULL, "amd_dimm_create: range create failed\n"); 48520c794b3Sgavinm return (-1); 48620c794b3Sgavinm } 48720c794b3Sgavinm 48820c794b3Sgavinm for (i = 0; i < ndimm; i++) { 48920c794b3Sgavinm if (nvlist_lookup_uint64(dimmarr[i], "num", &num) != 0) { 49020c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: dimm num property " 49120c794b3Sgavinm "missing\n"); 49220c794b3Sgavinm continue; 49320c794b3Sgavinm } 49420c794b3Sgavinm 49520c794b3Sgavinm if (mkrsrc(mod, pnode, name, num, auth, &fmri) < 0) { 49620c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: mkrsrc failed\n"); 49720c794b3Sgavinm continue; 49820c794b3Sgavinm } 499074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 500*efd31e1dSTrang Do smbid = memnode_to_smbiosid(mod, chip_smbid, 501*efd31e1dSTrang Do DIMM_NODE_NAME, i, NULL); 502074bb90dSTom Pothier serial = chip_serial_smbios_get(mod, smbid); 503074bb90dSTom Pothier part = chip_part_smbios_get(mod, smbid); 504074bb90dSTom Pothier rev = chip_rev_smbios_get(mod, smbid); 505074bb90dSTom Pothier perr += nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, 506074bb90dSTom Pothier serial); 507074bb90dSTom Pothier perr += nvlist_add_string(fmri, FM_FMRI_HC_PART, 508074bb90dSTom Pothier part); 509074bb90dSTom Pothier perr += nvlist_add_string(fmri, FM_FMRI_HC_REVISION, 510074bb90dSTom Pothier rev); 511074bb90dSTom Pothier 512074bb90dSTom Pothier if (perr != 0) 513074bb90dSTom Pothier whinge(mod, NULL, "amd_dimm_create:" 514074bb90dSTom Pothier "nvlist_add_string failed\n"); 515074bb90dSTom Pothier } 51620c794b3Sgavinm 51720c794b3Sgavinm if ((dimmnode = topo_node_bind(mod, pnode, name, num, fmri)) 51820c794b3Sgavinm == NULL) { 51920c794b3Sgavinm nvlist_free(fmri); 52020c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: node bind " 52120c794b3Sgavinm "failed\n"); 52220c794b3Sgavinm continue; 52320c794b3Sgavinm } 52420c794b3Sgavinm 525074bb90dSTom Pothier if (!FM_AWARE_SMBIOS(mod)) 526074bb90dSTom Pothier if (topo_method_register(mod, 527074bb90dSTom Pothier dimmnode, dimm_methods) < 0) 528074bb90dSTom Pothier whinge(mod, &nerr, "amd_dimm_create: " 529074bb90dSTom Pothier "topo_method_register failed"); 530074bb90dSTom Pothier 531074bb90dSTom Pothier (void) topo_pgroup_create(dimmnode, &dimm_pgroup, &err); 532074bb90dSTom Pothier 533074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 534074bb90dSTom Pothier char *label; 535074bb90dSTom Pothier 536074bb90dSTom Pothier nvlist_free(fmri); 537074bb90dSTom Pothier (void) topo_node_resource(dimmnode, 538074bb90dSTom Pothier &fmri, &err); 539074bb90dSTom Pothier 540074bb90dSTom Pothier label = (char *)chip_label_smbios_get(mod, 541074bb90dSTom Pothier pnode, smbid, NULL); 542074bb90dSTom Pothier if (topo_node_label_set(dimmnode, label, 543074bb90dSTom Pothier &perr) == -1) 544074bb90dSTom Pothier topo_mod_dprintf(mod, "Failed" 545074bb90dSTom Pothier "to set label\n"); 546074bb90dSTom Pothier topo_mod_strfree(mod, label); 547074bb90dSTom Pothier 548074bb90dSTom Pothier (void) topo_prop_set_string(dimmnode, PGNAME(DIMM), 549074bb90dSTom Pothier FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, 550074bb90dSTom Pothier serial, &err); 551074bb90dSTom Pothier (void) topo_prop_set_string(dimmnode, PGNAME(DIMM), 552074bb90dSTom Pothier FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, 553074bb90dSTom Pothier part, &err); 554074bb90dSTom Pothier (void) topo_prop_set_string(dimmnode, PGNAME(DIMM), 555074bb90dSTom Pothier FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, 556074bb90dSTom Pothier rev, &err); 557074bb90dSTom Pothier } 55820c794b3Sgavinm 559e4b86885SCheng Sean Ye (void) topo_node_asru_set(dimmnode, fmri, 0, &err); 56020c794b3Sgavinm (void) topo_node_fru_set(dimmnode, fmri, 0, &err); 56120c794b3Sgavinm nvlist_free(fmri); 56220c794b3Sgavinm 56320c794b3Sgavinm for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; 56420c794b3Sgavinm nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { 56520c794b3Sgavinm if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY && 56620c794b3Sgavinm strcmp(nvpair_name(nvp), "csnums") == 0 || 56720c794b3Sgavinm nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY && 56820c794b3Sgavinm strcmp(nvpair_name(nvp), "csnames") == 0) 56920c794b3Sgavinm continue; /* used in amd_rank_create() */ 57020c794b3Sgavinm 57120c794b3Sgavinm nerr += nvprop_add(mod, nvp, PGNAME(DIMM), dimmnode); 57220c794b3Sgavinm } 57320c794b3Sgavinm 57420c794b3Sgavinm nerr += amd_rank_create(mod, dimmnode, dimmarr[i], auth); 57520c794b3Sgavinm } 57620c794b3Sgavinm 57720c794b3Sgavinm return (nerr == 0 ? 0 : -1); 57820c794b3Sgavinm } 57920c794b3Sgavinm 58020c794b3Sgavinm static int 58120c794b3Sgavinm amd_cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc, 58220c794b3Sgavinm nvlist_t *auth) 58320c794b3Sgavinm { 58420c794b3Sgavinm int i, err, nerr = 0; 58520c794b3Sgavinm nvpair_t *nvp; 58620c794b3Sgavinm tnode_t *csnode; 58720c794b3Sgavinm nvlist_t *fmri, **csarr = NULL; 58820c794b3Sgavinm uint64_t csnum; 58920c794b3Sgavinm uint_t ncs; 59020c794b3Sgavinm 59120c794b3Sgavinm if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) 59220c794b3Sgavinm return (-1); 59320c794b3Sgavinm 59420c794b3Sgavinm if (ncs == 0) 59520c794b3Sgavinm return (0); /* no chip-selects configured on this node */ 59620c794b3Sgavinm 59720c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, MAX_CSNUM) < 0) 59820c794b3Sgavinm return (-1); 59920c794b3Sgavinm 60020c794b3Sgavinm for (i = 0; i < ncs; i++) { 60120c794b3Sgavinm if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { 60220c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: cs num property " 60320c794b3Sgavinm "missing\n"); 60420c794b3Sgavinm continue; 60520c794b3Sgavinm } 60620c794b3Sgavinm 60720c794b3Sgavinm if (mkrsrc(mod, pnode, name, csnum, auth, &fmri) != 0) { 60820c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: mkrsrc failed\n"); 60920c794b3Sgavinm continue; 61020c794b3Sgavinm } 61120c794b3Sgavinm 61220c794b3Sgavinm if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri)) 61320c794b3Sgavinm == NULL) { 61420c794b3Sgavinm nvlist_free(fmri); 61520c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: node bind failed\n"); 61620c794b3Sgavinm continue; 61720c794b3Sgavinm } 61820c794b3Sgavinm 61920c794b3Sgavinm cs_fmri[csnum] = fmri; /* nvlist will be freed in mc_create */ 62020c794b3Sgavinm 62120c794b3Sgavinm (void) topo_node_asru_set(csnode, fmri, 0, &err); 62220c794b3Sgavinm 623b7d3956bSstephh (void) topo_node_fru_set(csnode, fmri, 0, &err); 624b7d3956bSstephh 62520c794b3Sgavinm (void) topo_pgroup_create(csnode, &cs_pgroup, &err); 62620c794b3Sgavinm 62720c794b3Sgavinm for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; 62820c794b3Sgavinm nvp = nvlist_next_nvpair(csarr[i], nvp)) { 62920c794b3Sgavinm nerr += nvprop_add(mod, nvp, PGNAME(CS), csnode); 63020c794b3Sgavinm } 63120c794b3Sgavinm } 63220c794b3Sgavinm 63320c794b3Sgavinm return (nerr == 0 ? 0 : -1); 63420c794b3Sgavinm } 63520c794b3Sgavinm 63620c794b3Sgavinm static int 63720c794b3Sgavinm amd_dramchan_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 63820c794b3Sgavinm nvlist_t *auth) 63920c794b3Sgavinm { 64020c794b3Sgavinm tnode_t *chnode; 64120c794b3Sgavinm nvlist_t *fmri; 64220c794b3Sgavinm char *socket; 64320c794b3Sgavinm int i, nchan; 644b7d3956bSstephh nvlist_t *pfmri = NULL; 64520c794b3Sgavinm int err, nerr = 0; 64620c794b3Sgavinm 64720c794b3Sgavinm /* 64820c794b3Sgavinm * We will enumerate the number of channels present even if only 64920c794b3Sgavinm * channel A is in use (i.e., running in 64-bit mode). Only 65020c794b3Sgavinm * the socket 754 package has a single channel. 65120c794b3Sgavinm */ 65220c794b3Sgavinm if (topo_prop_get_string(pnode, PGNAME(MCT), "socket", 65320c794b3Sgavinm &socket, &err) == 0 && strcmp(socket, "Socket 754") == 0) 65420c794b3Sgavinm nchan = 1; 65520c794b3Sgavinm else 65620c794b3Sgavinm nchan = 2; 65720c794b3Sgavinm 65820c794b3Sgavinm topo_mod_strfree(mod, socket); 65920c794b3Sgavinm 66020c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nchan - 1) < 0) 66120c794b3Sgavinm return (-1); 66220c794b3Sgavinm 663b7d3956bSstephh (void) topo_node_fru(pnode, &pfmri, NULL, &err); 664b7d3956bSstephh 66520c794b3Sgavinm for (i = 0; i < nchan; i++) { 66620c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 66720c794b3Sgavinm whinge(mod, &nerr, "amd_dramchan_create: mkrsrc " 66820c794b3Sgavinm "failed\n"); 66920c794b3Sgavinm continue; 67020c794b3Sgavinm } 67120c794b3Sgavinm 67220c794b3Sgavinm if ((chnode = topo_node_bind(mod, pnode, name, i, fmri)) 67320c794b3Sgavinm == NULL) { 67420c794b3Sgavinm nvlist_free(fmri); 67520c794b3Sgavinm whinge(mod, &nerr, "amd_dramchan_create: node bind " 67620c794b3Sgavinm "failed\n"); 67720c794b3Sgavinm continue; 67820c794b3Sgavinm } 67920c794b3Sgavinm 680b7d3956bSstephh (void) topo_node_asru_set(chnode, fmri, 0, &err); 681b7d3956bSstephh if (pfmri) 682b7d3956bSstephh (void) topo_node_fru_set(chnode, pfmri, 0, &err); 683b7d3956bSstephh 68420c794b3Sgavinm nvlist_free(fmri); 68520c794b3Sgavinm 68620c794b3Sgavinm (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 68720c794b3Sgavinm 68820c794b3Sgavinm (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 68920c794b3Sgavinm TOPO_PROP_IMMUTABLE, i == 0 ? "A" : "B", &err); 69020c794b3Sgavinm } 691b7d3956bSstephh if (pfmri) 692b7d3956bSstephh nvlist_free(pfmri); 69320c794b3Sgavinm 69420c794b3Sgavinm return (nerr == 0 ? 0 : -1); 69520c794b3Sgavinm } 69620c794b3Sgavinm 69720c794b3Sgavinm static int 69820c794b3Sgavinm amd_htconfig(topo_mod_t *mod, tnode_t *cnode, nvlist_t *htnvl) 69920c794b3Sgavinm { 70020c794b3Sgavinm nvpair_t *nvp; 70120c794b3Sgavinm int nerr = 0; 70220c794b3Sgavinm 70320c794b3Sgavinm if (strcmp(topo_node_name(cnode), CHIP_NODE_NAME) != 0) { 70420c794b3Sgavinm whinge(mod, &nerr, "amd_htconfig: must pass a chip node!"); 70520c794b3Sgavinm return (-1); 70620c794b3Sgavinm } 70720c794b3Sgavinm 70820c794b3Sgavinm for (nvp = nvlist_next_nvpair(htnvl, NULL); nvp != NULL; 70920c794b3Sgavinm nvp = nvlist_next_nvpair(htnvl, nvp)) { 71020c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(CHIP), cnode) != 0) 71120c794b3Sgavinm nerr++; 71220c794b3Sgavinm } 71320c794b3Sgavinm 71420c794b3Sgavinm return (nerr == 0 ? 0 : -1); 71520c794b3Sgavinm } 71620c794b3Sgavinm 71720c794b3Sgavinm void 7188031591dSSrihari Venkatesan amd_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *pnode, 7198031591dSSrihari Venkatesan const char *name, nvlist_t *auth, int32_t procnodeid, 7208031591dSSrihari Venkatesan int32_t procnodes_per_pkg, int family, 7218031591dSSrihari Venkatesan int model, int *nerrp) 72220c794b3Sgavinm { 72320c794b3Sgavinm tnode_t *mcnode; 7245895e34bSSrihari Venkatesan nvlist_t *rfmri, *fmri; 72520c794b3Sgavinm nvpair_t *nvp; 72620c794b3Sgavinm nvlist_t *mc = NULL; 7271db96d3bSCheng Sean Ye int i, err; 7288031591dSSrihari Venkatesan int mcnum = procnodeid % procnodes_per_pkg; 729074bb90dSTom Pothier char *serial = NULL; 730074bb90dSTom Pothier char *part = NULL; 731074bb90dSTom Pothier char *rev = NULL; 73220c794b3Sgavinm 73320c794b3Sgavinm /* 73420c794b3Sgavinm * Return with no error for anything before AMD family 0xf - we 7358031591dSSrihari Venkatesan * won't generate even a generic memory topology for earlier 73620c794b3Sgavinm * families. 73720c794b3Sgavinm */ 73820c794b3Sgavinm if (family < 0xf) 73920c794b3Sgavinm return; 74020c794b3Sgavinm 7418031591dSSrihari Venkatesan if (topo_node_lookup(pnode, name, mcnum) != NULL) 7428031591dSSrihari Venkatesan return; 7438031591dSSrihari Venkatesan 744074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 7455895e34bSSrihari Venkatesan (void) topo_node_resource(pnode, &rfmri, &err); 7465895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "serial", &serial); 7475895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "part", &part); 7485895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "revision", &rev); 749074bb90dSTom Pothier } 750074bb90dSTom Pothier 7518031591dSSrihari Venkatesan if (mkrsrc(mod, pnode, name, mcnum, auth, &fmri) != 0) { 7525895e34bSSrihari Venkatesan if (FM_AWARE_SMBIOS(mod)) 7535895e34bSSrihari Venkatesan nvlist_free(rfmri); 75420c794b3Sgavinm whinge(mod, nerrp, "mc_create: mkrsrc failed\n"); 75520c794b3Sgavinm return; 75620c794b3Sgavinm } 75720c794b3Sgavinm 758074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 759074bb90dSTom Pothier (void) nvlist_add_string(fmri, "serial", serial); 760074bb90dSTom Pothier (void) nvlist_add_string(fmri, "part", part); 761074bb90dSTom Pothier (void) nvlist_add_string(fmri, "revision", rev); 7625895e34bSSrihari Venkatesan nvlist_free(rfmri); 763074bb90dSTom Pothier } 764074bb90dSTom Pothier 7658031591dSSrihari Venkatesan if ((mcnode = topo_node_bind(mod, pnode, name, mcnum, 76620c794b3Sgavinm fmri)) == NULL) { 76720c794b3Sgavinm nvlist_free(fmri); 76820c794b3Sgavinm whinge(mod, nerrp, "mc_create: mc bind failed\n"); 76920c794b3Sgavinm return; 77020c794b3Sgavinm } 7711db96d3bSCheng Sean Ye if (topo_node_fru_set(mcnode, NULL, 0, &err) < 0) 7721db96d3bSCheng Sean Ye whinge(mod, nerrp, "mc_create: topo_node_fru_set failed\n"); 7731db96d3bSCheng Sean Ye 774074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) { 775074bb90dSTom Pothier if (topo_node_label_set(mcnode, NULL, &err) == -1) 776074bb90dSTom Pothier topo_mod_dprintf(mod, "Failed to set label\n"); 777074bb90dSTom Pothier } 778074bb90dSTom Pothier 77920c794b3Sgavinm nvlist_free(fmri); 78020c794b3Sgavinm 7818031591dSSrihari Venkatesan if (topo_pgroup_create(mcnode, &mc_pgroup, &err) < 0) 7828031591dSSrihari Venkatesan whinge(mod, nerrp, "mc_create: topo_pgroup_create failed\n"); 7838031591dSSrihari Venkatesan 7848031591dSSrihari Venkatesan if (topo_prop_set_int32(mcnode, PGNAME(MCT), MCT_PROCNODE_ID, 7858031591dSSrihari Venkatesan TOPO_PROP_IMMUTABLE, procnodeid, nerrp) != 0) 7868031591dSSrihari Venkatesan whinge(mod, nerrp, "mc_create: topo_prop_set_int32 failed to" 7878031591dSSrihari Venkatesan "add node id\n"); 7888031591dSSrihari Venkatesan 78920c794b3Sgavinm if ((mc = amd_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL) { 79020c794b3Sgavinm /* 79120c794b3Sgavinm * If a memory-controller driver exists for this chip model 79220c794b3Sgavinm * it has not attached or has otherwise malfunctioned; 79320c794b3Sgavinm * alternatively no memory-controller driver exists for this 79420c794b3Sgavinm * (presumably newly-released) cpu model. We fallback to 79520c794b3Sgavinm * creating a generic maximal topology. 79620c794b3Sgavinm */ 797074bb90dSTom Pothier if (amd_generic_mc_create(mod, smbid, pnode, mcnode, 7988031591dSSrihari Venkatesan family, model, auth) != 0) 7991db96d3bSCheng Sean Ye whinge(mod, nerrp, 8001db96d3bSCheng Sean Ye "mc_create: amd_generic_mc_create failed\n"); 80120c794b3Sgavinm return; 80220c794b3Sgavinm } 80320c794b3Sgavinm 80420c794b3Sgavinm /* 80520c794b3Sgavinm * Add memory controller properties 80620c794b3Sgavinm */ 80720c794b3Sgavinm for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; 80820c794b3Sgavinm nvp = nvlist_next_nvpair(mc, nvp)) { 80920c794b3Sgavinm char *name = nvpair_name(nvp); 81020c794b3Sgavinm data_type_t type = nvpair_type(nvp); 81120c794b3Sgavinm 81220c794b3Sgavinm if (type == DATA_TYPE_NVLIST_ARRAY && 81320c794b3Sgavinm (strcmp(name, "cslist") == 0 || 81420c794b3Sgavinm strcmp(name, "dimmlist") == 0)) { 81520c794b3Sgavinm continue; 81620c794b3Sgavinm } else if (type == DATA_TYPE_UINT8 && 81720c794b3Sgavinm strcmp(name, MC_NVLIST_VERSTR) == 0) { 81820c794b3Sgavinm continue; 81920c794b3Sgavinm } else if (type == DATA_TYPE_NVLIST && 82020c794b3Sgavinm strcmp(name, "htconfig") == 0) { 82120c794b3Sgavinm nvlist_t *htnvl; 82220c794b3Sgavinm 82320c794b3Sgavinm (void) nvpair_value_nvlist(nvp, &htnvl); 82420c794b3Sgavinm if (amd_htconfig(mod, pnode, htnvl) != 0) 8251db96d3bSCheng Sean Ye whinge(mod, nerrp, 8261db96d3bSCheng Sean Ye "mc_create: amd_htconfig failed\n"); 82720c794b3Sgavinm } else { 82820c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(MCT), mcnode) != 0) 8291db96d3bSCheng Sean Ye whinge(mod, nerrp, 8301db96d3bSCheng Sean Ye "mc_create: nvprop_add failed\n"); 83120c794b3Sgavinm } 83220c794b3Sgavinm } 83320c794b3Sgavinm 83420c794b3Sgavinm if (amd_dramchan_create(mod, mcnode, CHAN_NODE_NAME, auth) != 0 || 83520c794b3Sgavinm amd_cs_create(mod, mcnode, CS_NODE_NAME, mc, auth) != 0 || 836074bb90dSTom Pothier amd_dimm_create(mod, smbid, mcnode, DIMM_NODE_NAME, mc, auth) != 0) 8371db96d3bSCheng Sean Ye whinge(mod, nerrp, "mc_create: create children failed\n"); 83820c794b3Sgavinm 83920c794b3Sgavinm /* 84020c794b3Sgavinm * Free the fmris for the chip-selects allocated in amd_cs_create 84120c794b3Sgavinm */ 84220c794b3Sgavinm for (i = 0; i < MC_CHIP_NCS; i++) { 84320c794b3Sgavinm if (cs_fmri[i] != NULL) { 84420c794b3Sgavinm nvlist_free(cs_fmri[i]); 84520c794b3Sgavinm cs_fmri[i] = NULL; 84620c794b3Sgavinm } 84720c794b3Sgavinm } 84820c794b3Sgavinm 84920c794b3Sgavinm nvlist_free(mc); 85020c794b3Sgavinm } 851