1*20c794b3Sgavinm /* 2*20c794b3Sgavinm * CDDL HEADER START 3*20c794b3Sgavinm * 4*20c794b3Sgavinm * The contents of this file are subject to the terms of the 5*20c794b3Sgavinm * Common Development and Distribution License (the "License"). 6*20c794b3Sgavinm * You may not use this file except in compliance with the License. 7*20c794b3Sgavinm * 8*20c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*20c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 10*20c794b3Sgavinm * See the License for the specific language governing permissions 11*20c794b3Sgavinm * and limitations under the License. 12*20c794b3Sgavinm * 13*20c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 14*20c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*20c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 16*20c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 17*20c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 18*20c794b3Sgavinm * 19*20c794b3Sgavinm * CDDL HEADER END 20*20c794b3Sgavinm */ 21*20c794b3Sgavinm 22*20c794b3Sgavinm /* 23*20c794b3Sgavinm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*20c794b3Sgavinm * Use is subject to license terms. 25*20c794b3Sgavinm */ 26*20c794b3Sgavinm 27*20c794b3Sgavinm #pragma ident "%Z%%M% %I% %E% SMI" 28*20c794b3Sgavinm 29*20c794b3Sgavinm /* 30*20c794b3Sgavinm * AMD memory enumeration 31*20c794b3Sgavinm */ 32*20c794b3Sgavinm 33*20c794b3Sgavinm #include <sys/types.h> 34*20c794b3Sgavinm #include <unistd.h> 35*20c794b3Sgavinm #include <stropts.h> 36*20c794b3Sgavinm #include <sys/fm/protocol.h> 37*20c794b3Sgavinm #include <sys/mc.h> 38*20c794b3Sgavinm #include <sys/mc_amd.h> 39*20c794b3Sgavinm #include <fm/topo_mod.h> 40*20c794b3Sgavinm #include <strings.h> 41*20c794b3Sgavinm #include <sys/stat.h> 42*20c794b3Sgavinm #include <fcntl.h> 43*20c794b3Sgavinm 44*20c794b3Sgavinm #include "chip.h" 45*20c794b3Sgavinm 46*20c794b3Sgavinm #define MAX_CHANNUM 1 47*20c794b3Sgavinm #define MAX_DIMMNUM 7 48*20c794b3Sgavinm #define MAX_CSNUM 7 49*20c794b3Sgavinm 50*20c794b3Sgavinm static const topo_pgroup_info_t cs_pgroup = 51*20c794b3Sgavinm { PGNAME(CS), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 52*20c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup = 53*20c794b3Sgavinm { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 54*20c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup = 55*20c794b3Sgavinm { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 56*20c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup = 57*20c794b3Sgavinm { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 58*20c794b3Sgavinm static const topo_pgroup_info_t chan_pgroup = 59*20c794b3Sgavinm { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 60*20c794b3Sgavinm 61*20c794b3Sgavinm static const topo_method_t dimm_methods[] = { 62*20c794b3Sgavinm { SIMPLE_DIMM_LBL, "Property method", 0, 63*20c794b3Sgavinm TOPO_STABILITY_INTERNAL, simple_dimm_label}, 64*20c794b3Sgavinm { SIMPLE_DIMM_LBL_MP, "Property method", 0, 65*20c794b3Sgavinm TOPO_STABILITY_INTERNAL, simple_dimm_label_mp}, 66*20c794b3Sgavinm { SEQ_DIMM_LBL, "Property method", 0, 67*20c794b3Sgavinm TOPO_STABILITY_INTERNAL, seq_dimm_label}, 68*20c794b3Sgavinm { NULL } 69*20c794b3Sgavinm }; 70*20c794b3Sgavinm 71*20c794b3Sgavinm static const topo_method_t rank_methods[] = { 72*20c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 73*20c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 74*20c794b3Sgavinm mem_asru_compute }, 75*20c794b3Sgavinm { NULL } 76*20c794b3Sgavinm }; 77*20c794b3Sgavinm 78*20c794b3Sgavinm static const topo_method_t gen_cs_methods[] = { 79*20c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 80*20c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 81*20c794b3Sgavinm mem_asru_compute }, 82*20c794b3Sgavinm { NULL } 83*20c794b3Sgavinm }; 84*20c794b3Sgavinm 85*20c794b3Sgavinm static nvlist_t *cs_fmri[MC_CHIP_NCS]; 86*20c794b3Sgavinm 87*20c794b3Sgavinm /* 88*20c794b3Sgavinm * Called when there is no memory-controller driver to provide topology 89*20c794b3Sgavinm * information. Generate a maximal memory topology that is appropriate 90*20c794b3Sgavinm * for the chip revision. The memory-controller node has already been 91*20c794b3Sgavinm * bound as mcnode, and the parent of that is cnode. 92*20c794b3Sgavinm * 93*20c794b3Sgavinm * We create a tree of dram-channel and chip-select nodes below the 94*20c794b3Sgavinm * memory-controller node. There will be two dram channels and 8 chip-selects 95*20c794b3Sgavinm * below each, regardless of actual socket type, processor revision and so on. 96*20c794b3Sgavinm * This is adequate for generic diagnosis up to family 0x10 revision C. 97*20c794b3Sgavinm * When support for revision D is implemented (or maybe C) we should take 98*20c794b3Sgavinm * the opportunity to rework the topology tree completely (socket change will 99*20c794b3Sgavinm * mean there can be no diagnosis history tied to the topology). 100*20c794b3Sgavinm */ 101*20c794b3Sgavinm /*ARGSUSED*/ 102*20c794b3Sgavinm static int 103*20c794b3Sgavinm amd_generic_mc_create(topo_mod_t *mod, tnode_t *cnode, tnode_t *mcnode, 104*20c794b3Sgavinm int family, int model, int stepping, nvlist_t *auth) 105*20c794b3Sgavinm { 106*20c794b3Sgavinm int chan, cs; 107*20c794b3Sgavinm 108*20c794b3Sgavinm /* 109*20c794b3Sgavinm * Elsewhere we have already returned for families less than 0xf. 110*20c794b3Sgavinm * This "generic" topology is adequate for all of family 0xf and 111*20c794b3Sgavinm * for revisions A, B and C of family 0x10 (A = model 0, B = model 1, 112*20c794b3Sgavinm * we'll guess C = model 3 at this point). 113*20c794b3Sgavinm */ 114*20c794b3Sgavinm if (family > 0x10 || (family == 0x10 && model > 3)) 115*20c794b3Sgavinm return (1); 116*20c794b3Sgavinm 117*20c794b3Sgavinm if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0, 118*20c794b3Sgavinm MAX_CHANNUM) < 0) { 119*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: range create for " 120*20c794b3Sgavinm "channels failed\n"); 121*20c794b3Sgavinm return (-1); 122*20c794b3Sgavinm } 123*20c794b3Sgavinm 124*20c794b3Sgavinm for (chan = 0; chan <= MAX_CHANNUM; chan++) { 125*20c794b3Sgavinm tnode_t *chnode; 126*20c794b3Sgavinm nvlist_t *fmri; 127*20c794b3Sgavinm int err; 128*20c794b3Sgavinm 129*20c794b3Sgavinm if (mkrsrc(mod, mcnode, CHAN_NODE_NAME, chan, auth, 130*20c794b3Sgavinm &fmri) != 0) { 131*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: mkrsrc " 132*20c794b3Sgavinm "failed\n"); 133*20c794b3Sgavinm return (-1); 134*20c794b3Sgavinm } 135*20c794b3Sgavinm 136*20c794b3Sgavinm if ((chnode = topo_node_bind(mod, mcnode, CHAN_NODE_NAME, 137*20c794b3Sgavinm chan, fmri)) == NULL) { 138*20c794b3Sgavinm nvlist_free(fmri); 139*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: node " 140*20c794b3Sgavinm "bind failed\n"); 141*20c794b3Sgavinm return (-1); 142*20c794b3Sgavinm } 143*20c794b3Sgavinm 144*20c794b3Sgavinm nvlist_free(fmri); 145*20c794b3Sgavinm 146*20c794b3Sgavinm (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 147*20c794b3Sgavinm 148*20c794b3Sgavinm (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 149*20c794b3Sgavinm TOPO_PROP_IMMUTABLE, chan == 0 ? "A" : "B", &err); 150*20c794b3Sgavinm 151*20c794b3Sgavinm if (topo_node_range_create(mod, chnode, CS_NODE_NAME, 152*20c794b3Sgavinm 0, MAX_CSNUM) < 0) { 153*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 154*20c794b3Sgavinm "range create for cs failed\n"); 155*20c794b3Sgavinm return (-1); 156*20c794b3Sgavinm } 157*20c794b3Sgavinm 158*20c794b3Sgavinm for (cs = 0; cs <= MAX_CSNUM; cs++) { 159*20c794b3Sgavinm tnode_t *csnode; 160*20c794b3Sgavinm 161*20c794b3Sgavinm if (mkrsrc(mod, chnode, CS_NODE_NAME, cs, auth, 162*20c794b3Sgavinm &fmri) != 0) { 163*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 164*20c794b3Sgavinm "mkrsrc for cs failed\n"); 165*20c794b3Sgavinm return (-1); 166*20c794b3Sgavinm } 167*20c794b3Sgavinm 168*20c794b3Sgavinm if ((csnode = topo_node_bind(mod, chnode, CS_NODE_NAME, 169*20c794b3Sgavinm cs, fmri)) == NULL) { 170*20c794b3Sgavinm nvlist_free(fmri); 171*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 172*20c794b3Sgavinm "bind for cs failed\n"); 173*20c794b3Sgavinm return (-1); 174*20c794b3Sgavinm } 175*20c794b3Sgavinm 176*20c794b3Sgavinm /* 177*20c794b3Sgavinm * Dynamic ASRU for page faults within a chip-select. 178*20c794b3Sgavinm * The topology does not represent pages (there are 179*20c794b3Sgavinm * too many) so when a page is faulted we generate 180*20c794b3Sgavinm * an ASRU to represent the individual page. 181*20c794b3Sgavinm */ 182*20c794b3Sgavinm if (topo_method_register(mod, csnode, 183*20c794b3Sgavinm gen_cs_methods) < 0) 184*20c794b3Sgavinm whinge(mod, NULL, "amd_generic_mc_create: " 185*20c794b3Sgavinm "method registration failed\n"); 186*20c794b3Sgavinm 187*20c794b3Sgavinm (void) topo_node_asru_set(csnode, fmri, 188*20c794b3Sgavinm TOPO_ASRU_COMPUTE, &err); 189*20c794b3Sgavinm 190*20c794b3Sgavinm nvlist_free(fmri); 191*20c794b3Sgavinm } 192*20c794b3Sgavinm } 193*20c794b3Sgavinm 194*20c794b3Sgavinm return (0); 195*20c794b3Sgavinm } 196*20c794b3Sgavinm 197*20c794b3Sgavinm static nvlist_t * 198*20c794b3Sgavinm amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) 199*20c794b3Sgavinm { 200*20c794b3Sgavinm mc_snapshot_info_t mcs; 201*20c794b3Sgavinm void *buf = NULL; 202*20c794b3Sgavinm uint8_t ver; 203*20c794b3Sgavinm 204*20c794b3Sgavinm nvlist_t *nvl = NULL; 205*20c794b3Sgavinm char path[64]; 206*20c794b3Sgavinm int fd, err; 207*20c794b3Sgavinm 208*20c794b3Sgavinm (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 209*20c794b3Sgavinm fd = open(path, O_RDONLY); 210*20c794b3Sgavinm 211*20c794b3Sgavinm if (fd == -1) { 212*20c794b3Sgavinm /* 213*20c794b3Sgavinm * Some v20z and v40z systems may have had the 3rd-party 214*20c794b3Sgavinm * NWSnps packagae installed which installs a /dev/mc 215*20c794b3Sgavinm * link. So try again via /devices. 216*20c794b3Sgavinm */ 217*20c794b3Sgavinm (void) snprintf(path, sizeof (path), 218*20c794b3Sgavinm "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd", 219*20c794b3Sgavinm MC_AMD_DEV_OFFSET + id); 220*20c794b3Sgavinm fd = open(path, O_RDONLY); 221*20c794b3Sgavinm } 222*20c794b3Sgavinm 223*20c794b3Sgavinm if (fd == -1) 224*20c794b3Sgavinm return (NULL); /* do not whinge */ 225*20c794b3Sgavinm 226*20c794b3Sgavinm if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 227*20c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 228*20c794b3Sgavinm ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { 229*20c794b3Sgavinm 230*20c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s: %s\n", 231*20c794b3Sgavinm path, strerror(errno)); 232*20c794b3Sgavinm 233*20c794b3Sgavinm free(buf); 234*20c794b3Sgavinm (void) close(fd); 235*20c794b3Sgavinm return (NULL); 236*20c794b3Sgavinm } 237*20c794b3Sgavinm 238*20c794b3Sgavinm (void) close(fd); 239*20c794b3Sgavinm err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 240*20c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 241*20c794b3Sgavinm 242*20c794b3Sgavinm 243*20c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) { 244*20c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 245*20c794b3Sgavinm nvlist_free(nvl); 246*20c794b3Sgavinm return (NULL); 247*20c794b3Sgavinm } else if (ver != MC_NVLIST_VERS1) { 248*20c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 249*20c794b3Sgavinm nvlist_free(nvl); 250*20c794b3Sgavinm return (NULL); 251*20c794b3Sgavinm } 252*20c794b3Sgavinm 253*20c794b3Sgavinm return (err ? NULL : nvl); 254*20c794b3Sgavinm } 255*20c794b3Sgavinm 256*20c794b3Sgavinm int 257*20c794b3Sgavinm amd_rank_create(topo_mod_t *mod, tnode_t *pnode, nvlist_t *dimmnvl, 258*20c794b3Sgavinm nvlist_t *auth) 259*20c794b3Sgavinm { 260*20c794b3Sgavinm uint64_t *csnumarr; 261*20c794b3Sgavinm char **csnamearr; 262*20c794b3Sgavinm uint_t ncs, ncsname; 263*20c794b3Sgavinm tnode_t *ranknode; 264*20c794b3Sgavinm nvlist_t *fmri, *pfmri = NULL; 265*20c794b3Sgavinm uint64_t dsz, rsz; 266*20c794b3Sgavinm int nerr = 0; 267*20c794b3Sgavinm int err; 268*20c794b3Sgavinm int i; 269*20c794b3Sgavinm 270*20c794b3Sgavinm if (nvlist_lookup_uint64_array(dimmnvl, "csnums", &csnumarr, 271*20c794b3Sgavinm &ncs) != 0 || nvlist_lookup_string_array(dimmnvl, "csnames", 272*20c794b3Sgavinm &csnamearr, &ncsname) != 0 || ncs != ncsname) { 273*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: " 274*20c794b3Sgavinm "csnums/csnames extraction failed\n"); 275*20c794b3Sgavinm return (nerr); 276*20c794b3Sgavinm } 277*20c794b3Sgavinm 278*20c794b3Sgavinm if (topo_node_resource(pnode, &pfmri, &err) < 0) { 279*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: parent fmri lookup " 280*20c794b3Sgavinm "failed\n"); 281*20c794b3Sgavinm return (nerr); 282*20c794b3Sgavinm } 283*20c794b3Sgavinm 284*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, RANK_NODE_NAME, 0, ncs) < 0) { 285*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: range create failed\n"); 286*20c794b3Sgavinm nvlist_free(pfmri); 287*20c794b3Sgavinm return (nerr); 288*20c794b3Sgavinm } 289*20c794b3Sgavinm 290*20c794b3Sgavinm if (topo_prop_get_uint64(pnode, PGNAME(DIMM), "size", &dsz, 291*20c794b3Sgavinm &err) == 0) { 292*20c794b3Sgavinm rsz = dsz / ncs; 293*20c794b3Sgavinm } else { 294*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: parent dimm has no " 295*20c794b3Sgavinm "size\n"); 296*20c794b3Sgavinm return (nerr); 297*20c794b3Sgavinm } 298*20c794b3Sgavinm 299*20c794b3Sgavinm for (i = 0; i < ncs; i++) { 300*20c794b3Sgavinm if (mkrsrc(mod, pnode, RANK_NODE_NAME, i, auth, &fmri) < 0) { 301*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: mkrsrc failed\n"); 302*20c794b3Sgavinm continue; 303*20c794b3Sgavinm } 304*20c794b3Sgavinm 305*20c794b3Sgavinm if ((ranknode = topo_node_bind(mod, pnode, RANK_NODE_NAME, i, 306*20c794b3Sgavinm fmri)) == NULL) { 307*20c794b3Sgavinm nvlist_free(fmri); 308*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: node bind " 309*20c794b3Sgavinm "failed\n"); 310*20c794b3Sgavinm continue; 311*20c794b3Sgavinm } 312*20c794b3Sgavinm 313*20c794b3Sgavinm nvlist_free(fmri); 314*20c794b3Sgavinm 315*20c794b3Sgavinm (void) topo_node_fru_set(ranknode, pfmri, 0, &err); 316*20c794b3Sgavinm 317*20c794b3Sgavinm /* 318*20c794b3Sgavinm * If a rank is faulted the asru is the associated 319*20c794b3Sgavinm * chip-select, but if a page within a rank is faulted 320*20c794b3Sgavinm * the asru is just that page. Hence the dual preconstructed 321*20c794b3Sgavinm * and computed ASRU. 322*20c794b3Sgavinm */ 323*20c794b3Sgavinm if (topo_method_register(mod, ranknode, rank_methods) < 0) 324*20c794b3Sgavinm whinge(mod, &nerr, "amd_rank_create: " 325*20c794b3Sgavinm "topo_method_register failed"); 326*20c794b3Sgavinm 327*20c794b3Sgavinm (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]], 328*20c794b3Sgavinm TOPO_ASRU_COMPUTE, &err); 329*20c794b3Sgavinm 330*20c794b3Sgavinm (void) topo_pgroup_create(ranknode, &rank_pgroup, &err); 331*20c794b3Sgavinm 332*20c794b3Sgavinm (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size", 333*20c794b3Sgavinm TOPO_PROP_IMMUTABLE, rsz, &err); 334*20c794b3Sgavinm 335*20c794b3Sgavinm (void) topo_prop_set_string(ranknode, PGNAME(RANK), "csname", 336*20c794b3Sgavinm TOPO_PROP_IMMUTABLE, csnamearr[i], &err); 337*20c794b3Sgavinm 338*20c794b3Sgavinm (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "csnum", 339*20c794b3Sgavinm TOPO_PROP_IMMUTABLE, csnumarr[i], &err); 340*20c794b3Sgavinm } 341*20c794b3Sgavinm 342*20c794b3Sgavinm nvlist_free(pfmri); 343*20c794b3Sgavinm 344*20c794b3Sgavinm return (nerr); 345*20c794b3Sgavinm } 346*20c794b3Sgavinm 347*20c794b3Sgavinm static int 348*20c794b3Sgavinm amd_dimm_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 349*20c794b3Sgavinm nvlist_t *mc, nvlist_t *auth) 350*20c794b3Sgavinm { 351*20c794b3Sgavinm int i, err, nerr = 0; 352*20c794b3Sgavinm nvpair_t *nvp; 353*20c794b3Sgavinm tnode_t *dimmnode; 354*20c794b3Sgavinm nvlist_t *fmri, *asru, **dimmarr = NULL; 355*20c794b3Sgavinm uint64_t num; 356*20c794b3Sgavinm uint_t ndimm; 357*20c794b3Sgavinm 358*20c794b3Sgavinm if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) { 359*20c794b3Sgavinm whinge(mod, NULL, "amd_dimm_create: dimmlist lookup failed\n"); 360*20c794b3Sgavinm return (-1); 361*20c794b3Sgavinm } 362*20c794b3Sgavinm 363*20c794b3Sgavinm if (ndimm == 0) 364*20c794b3Sgavinm return (0); /* no dimms present on this node */ 365*20c794b3Sgavinm 366*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, MAX_DIMMNUM) < 0) { 367*20c794b3Sgavinm whinge(mod, NULL, "amd_dimm_create: range create failed\n"); 368*20c794b3Sgavinm return (-1); 369*20c794b3Sgavinm } 370*20c794b3Sgavinm 371*20c794b3Sgavinm for (i = 0; i < ndimm; i++) { 372*20c794b3Sgavinm if (nvlist_lookup_uint64(dimmarr[i], "num", &num) != 0) { 373*20c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: dimm num property " 374*20c794b3Sgavinm "missing\n"); 375*20c794b3Sgavinm continue; 376*20c794b3Sgavinm } 377*20c794b3Sgavinm 378*20c794b3Sgavinm if (mkrsrc(mod, pnode, name, num, auth, &fmri) < 0) { 379*20c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: mkrsrc failed\n"); 380*20c794b3Sgavinm continue; 381*20c794b3Sgavinm } 382*20c794b3Sgavinm 383*20c794b3Sgavinm if ((dimmnode = topo_node_bind(mod, pnode, name, num, fmri)) 384*20c794b3Sgavinm == NULL) { 385*20c794b3Sgavinm nvlist_free(fmri); 386*20c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: node bind " 387*20c794b3Sgavinm "failed\n"); 388*20c794b3Sgavinm continue; 389*20c794b3Sgavinm } 390*20c794b3Sgavinm 391*20c794b3Sgavinm if (topo_method_register(mod, dimmnode, dimm_methods) < 0) 392*20c794b3Sgavinm whinge(mod, &nerr, "dimm_create: " 393*20c794b3Sgavinm "topo_method_register failed"); 394*20c794b3Sgavinm 395*20c794b3Sgavinm /* 396*20c794b3Sgavinm * Use the mem computation method directly to publish the asru 397*20c794b3Sgavinm * in the "mem" scheme. 398*20c794b3Sgavinm */ 399*20c794b3Sgavinm if (mem_asru_create(mod, fmri, &asru) == 0) { 400*20c794b3Sgavinm (void) topo_node_asru_set(dimmnode, asru, 0, &err); 401*20c794b3Sgavinm nvlist_free(asru); 402*20c794b3Sgavinm } else { 403*20c794b3Sgavinm 404*20c794b3Sgavinm nvlist_free(fmri); 405*20c794b3Sgavinm whinge(mod, &nerr, "amd_dimm_create: " 406*20c794b3Sgavinm "mem_asru_create failed\n"); 407*20c794b3Sgavinm continue; 408*20c794b3Sgavinm } 409*20c794b3Sgavinm 410*20c794b3Sgavinm (void) topo_node_fru_set(dimmnode, fmri, 0, &err); 411*20c794b3Sgavinm 412*20c794b3Sgavinm nvlist_free(fmri); 413*20c794b3Sgavinm 414*20c794b3Sgavinm (void) topo_pgroup_create(dimmnode, &dimm_pgroup, &err); 415*20c794b3Sgavinm 416*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; 417*20c794b3Sgavinm nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { 418*20c794b3Sgavinm if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY && 419*20c794b3Sgavinm strcmp(nvpair_name(nvp), "csnums") == 0 || 420*20c794b3Sgavinm nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY && 421*20c794b3Sgavinm strcmp(nvpair_name(nvp), "csnames") == 0) 422*20c794b3Sgavinm continue; /* used in amd_rank_create() */ 423*20c794b3Sgavinm 424*20c794b3Sgavinm nerr += nvprop_add(mod, nvp, PGNAME(DIMM), dimmnode); 425*20c794b3Sgavinm } 426*20c794b3Sgavinm 427*20c794b3Sgavinm nerr += amd_rank_create(mod, dimmnode, dimmarr[i], auth); 428*20c794b3Sgavinm } 429*20c794b3Sgavinm 430*20c794b3Sgavinm return (nerr == 0 ? 0 : -1); 431*20c794b3Sgavinm } 432*20c794b3Sgavinm 433*20c794b3Sgavinm static int 434*20c794b3Sgavinm amd_cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc, 435*20c794b3Sgavinm nvlist_t *auth) 436*20c794b3Sgavinm { 437*20c794b3Sgavinm int i, err, nerr = 0; 438*20c794b3Sgavinm nvpair_t *nvp; 439*20c794b3Sgavinm tnode_t *csnode; 440*20c794b3Sgavinm nvlist_t *fmri, **csarr = NULL; 441*20c794b3Sgavinm uint64_t csnum; 442*20c794b3Sgavinm uint_t ncs; 443*20c794b3Sgavinm 444*20c794b3Sgavinm if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) 445*20c794b3Sgavinm return (-1); 446*20c794b3Sgavinm 447*20c794b3Sgavinm if (ncs == 0) 448*20c794b3Sgavinm return (0); /* no chip-selects configured on this node */ 449*20c794b3Sgavinm 450*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, MAX_CSNUM) < 0) 451*20c794b3Sgavinm return (-1); 452*20c794b3Sgavinm 453*20c794b3Sgavinm for (i = 0; i < ncs; i++) { 454*20c794b3Sgavinm if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { 455*20c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: cs num property " 456*20c794b3Sgavinm "missing\n"); 457*20c794b3Sgavinm continue; 458*20c794b3Sgavinm } 459*20c794b3Sgavinm 460*20c794b3Sgavinm if (mkrsrc(mod, pnode, name, csnum, auth, &fmri) != 0) { 461*20c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: mkrsrc failed\n"); 462*20c794b3Sgavinm continue; 463*20c794b3Sgavinm } 464*20c794b3Sgavinm 465*20c794b3Sgavinm if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri)) 466*20c794b3Sgavinm == NULL) { 467*20c794b3Sgavinm nvlist_free(fmri); 468*20c794b3Sgavinm whinge(mod, &nerr, "amd_cs_create: node bind failed\n"); 469*20c794b3Sgavinm continue; 470*20c794b3Sgavinm } 471*20c794b3Sgavinm 472*20c794b3Sgavinm cs_fmri[csnum] = fmri; /* nvlist will be freed in mc_create */ 473*20c794b3Sgavinm 474*20c794b3Sgavinm (void) topo_node_asru_set(csnode, fmri, 0, &err); 475*20c794b3Sgavinm 476*20c794b3Sgavinm (void) topo_pgroup_create(csnode, &cs_pgroup, &err); 477*20c794b3Sgavinm 478*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; 479*20c794b3Sgavinm nvp = nvlist_next_nvpair(csarr[i], nvp)) { 480*20c794b3Sgavinm nerr += nvprop_add(mod, nvp, PGNAME(CS), csnode); 481*20c794b3Sgavinm } 482*20c794b3Sgavinm } 483*20c794b3Sgavinm 484*20c794b3Sgavinm return (nerr == 0 ? 0 : -1); 485*20c794b3Sgavinm } 486*20c794b3Sgavinm 487*20c794b3Sgavinm static int 488*20c794b3Sgavinm amd_dramchan_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 489*20c794b3Sgavinm nvlist_t *auth) 490*20c794b3Sgavinm { 491*20c794b3Sgavinm tnode_t *chnode; 492*20c794b3Sgavinm nvlist_t *fmri; 493*20c794b3Sgavinm char *socket; 494*20c794b3Sgavinm int i, nchan; 495*20c794b3Sgavinm int err, nerr = 0; 496*20c794b3Sgavinm 497*20c794b3Sgavinm /* 498*20c794b3Sgavinm * We will enumerate the number of channels present even if only 499*20c794b3Sgavinm * channel A is in use (i.e., running in 64-bit mode). Only 500*20c794b3Sgavinm * the socket 754 package has a single channel. 501*20c794b3Sgavinm */ 502*20c794b3Sgavinm if (topo_prop_get_string(pnode, PGNAME(MCT), "socket", 503*20c794b3Sgavinm &socket, &err) == 0 && strcmp(socket, "Socket 754") == 0) 504*20c794b3Sgavinm nchan = 1; 505*20c794b3Sgavinm else 506*20c794b3Sgavinm nchan = 2; 507*20c794b3Sgavinm 508*20c794b3Sgavinm topo_mod_strfree(mod, socket); 509*20c794b3Sgavinm 510*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nchan - 1) < 0) 511*20c794b3Sgavinm return (-1); 512*20c794b3Sgavinm 513*20c794b3Sgavinm for (i = 0; i < nchan; i++) { 514*20c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 515*20c794b3Sgavinm whinge(mod, &nerr, "amd_dramchan_create: mkrsrc " 516*20c794b3Sgavinm "failed\n"); 517*20c794b3Sgavinm continue; 518*20c794b3Sgavinm } 519*20c794b3Sgavinm 520*20c794b3Sgavinm if ((chnode = topo_node_bind(mod, pnode, name, i, fmri)) 521*20c794b3Sgavinm == NULL) { 522*20c794b3Sgavinm nvlist_free(fmri); 523*20c794b3Sgavinm whinge(mod, &nerr, "amd_dramchan_create: node bind " 524*20c794b3Sgavinm "failed\n"); 525*20c794b3Sgavinm continue; 526*20c794b3Sgavinm } 527*20c794b3Sgavinm 528*20c794b3Sgavinm nvlist_free(fmri); 529*20c794b3Sgavinm 530*20c794b3Sgavinm (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 531*20c794b3Sgavinm 532*20c794b3Sgavinm (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 533*20c794b3Sgavinm TOPO_PROP_IMMUTABLE, i == 0 ? "A" : "B", &err); 534*20c794b3Sgavinm } 535*20c794b3Sgavinm 536*20c794b3Sgavinm return (nerr == 0 ? 0 : -1); 537*20c794b3Sgavinm } 538*20c794b3Sgavinm 539*20c794b3Sgavinm static int 540*20c794b3Sgavinm amd_htconfig(topo_mod_t *mod, tnode_t *cnode, nvlist_t *htnvl) 541*20c794b3Sgavinm { 542*20c794b3Sgavinm nvpair_t *nvp; 543*20c794b3Sgavinm int nerr = 0; 544*20c794b3Sgavinm 545*20c794b3Sgavinm if (strcmp(topo_node_name(cnode), CHIP_NODE_NAME) != 0) { 546*20c794b3Sgavinm whinge(mod, &nerr, "amd_htconfig: must pass a chip node!"); 547*20c794b3Sgavinm return (-1); 548*20c794b3Sgavinm } 549*20c794b3Sgavinm 550*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(htnvl, NULL); nvp != NULL; 551*20c794b3Sgavinm nvp = nvlist_next_nvpair(htnvl, nvp)) { 552*20c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(CHIP), cnode) != 0) 553*20c794b3Sgavinm nerr++; 554*20c794b3Sgavinm } 555*20c794b3Sgavinm 556*20c794b3Sgavinm return (nerr == 0 ? 0 : -1); 557*20c794b3Sgavinm } 558*20c794b3Sgavinm 559*20c794b3Sgavinm void 560*20c794b3Sgavinm amd_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 561*20c794b3Sgavinm int family, int model, int stepping, int *nerrp) 562*20c794b3Sgavinm { 563*20c794b3Sgavinm tnode_t *mcnode; 564*20c794b3Sgavinm nvlist_t *fmri; 565*20c794b3Sgavinm nvpair_t *nvp; 566*20c794b3Sgavinm nvlist_t *mc = NULL; 567*20c794b3Sgavinm int i; 568*20c794b3Sgavinm 569*20c794b3Sgavinm /* 570*20c794b3Sgavinm * Return with no error for anything before AMD family 0xf - we 571*20c794b3Sgavinm * won't generate even a generic memory topolofy for earlier 572*20c794b3Sgavinm * families. 573*20c794b3Sgavinm */ 574*20c794b3Sgavinm if (family < 0xf) 575*20c794b3Sgavinm return; 576*20c794b3Sgavinm 577*20c794b3Sgavinm if (mkrsrc(mod, pnode, name, 0, auth, &fmri) != 0) { 578*20c794b3Sgavinm whinge(mod, nerrp, "mc_create: mkrsrc failed\n"); 579*20c794b3Sgavinm return; 580*20c794b3Sgavinm } 581*20c794b3Sgavinm 582*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) { 583*20c794b3Sgavinm nvlist_free(fmri); 584*20c794b3Sgavinm whinge(mod, nerrp, "mc_create: node range create failed\n"); 585*20c794b3Sgavinm return; 586*20c794b3Sgavinm } 587*20c794b3Sgavinm 588*20c794b3Sgavinm if ((mcnode = topo_node_bind(mod, pnode, name, 0, 589*20c794b3Sgavinm fmri)) == NULL) { 590*20c794b3Sgavinm nvlist_free(mc); 591*20c794b3Sgavinm topo_node_range_destroy(pnode, name); 592*20c794b3Sgavinm nvlist_free(fmri); 593*20c794b3Sgavinm whinge(mod, nerrp, "mc_create: mc bind failed\n"); 594*20c794b3Sgavinm return; 595*20c794b3Sgavinm } 596*20c794b3Sgavinm (void) topo_node_fru_set(mcnode, NULL, 0, nerrp); 597*20c794b3Sgavinm nvlist_free(fmri); 598*20c794b3Sgavinm 599*20c794b3Sgavinm if ((mc = amd_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL) { 600*20c794b3Sgavinm /* 601*20c794b3Sgavinm * If a memory-controller driver exists for this chip model 602*20c794b3Sgavinm * it has not attached or has otherwise malfunctioned; 603*20c794b3Sgavinm * alternatively no memory-controller driver exists for this 604*20c794b3Sgavinm * (presumably newly-released) cpu model. We fallback to 605*20c794b3Sgavinm * creating a generic maximal topology. 606*20c794b3Sgavinm */ 607*20c794b3Sgavinm if (amd_generic_mc_create(mod, pnode, mcnode, 608*20c794b3Sgavinm family, model, stepping, auth) != 0) 609*20c794b3Sgavinm ++*nerrp; 610*20c794b3Sgavinm return; 611*20c794b3Sgavinm } 612*20c794b3Sgavinm 613*20c794b3Sgavinm /* 614*20c794b3Sgavinm * Add memory controller properties 615*20c794b3Sgavinm */ 616*20c794b3Sgavinm (void) topo_pgroup_create(mcnode, &mc_pgroup, nerrp); 617*20c794b3Sgavinm 618*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; 619*20c794b3Sgavinm nvp = nvlist_next_nvpair(mc, nvp)) { 620*20c794b3Sgavinm char *name = nvpair_name(nvp); 621*20c794b3Sgavinm data_type_t type = nvpair_type(nvp); 622*20c794b3Sgavinm 623*20c794b3Sgavinm if (type == DATA_TYPE_NVLIST_ARRAY && 624*20c794b3Sgavinm (strcmp(name, "cslist") == 0 || 625*20c794b3Sgavinm strcmp(name, "dimmlist") == 0)) { 626*20c794b3Sgavinm continue; 627*20c794b3Sgavinm } else if (type == DATA_TYPE_UINT8 && 628*20c794b3Sgavinm strcmp(name, MC_NVLIST_VERSTR) == 0) { 629*20c794b3Sgavinm continue; 630*20c794b3Sgavinm } else if (type == DATA_TYPE_NVLIST && 631*20c794b3Sgavinm strcmp(name, "htconfig") == 0) { 632*20c794b3Sgavinm nvlist_t *htnvl; 633*20c794b3Sgavinm 634*20c794b3Sgavinm (void) nvpair_value_nvlist(nvp, &htnvl); 635*20c794b3Sgavinm if (amd_htconfig(mod, pnode, htnvl) != 0) 636*20c794b3Sgavinm ++*nerrp; 637*20c794b3Sgavinm } else { 638*20c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(MCT), mcnode) != 0) 639*20c794b3Sgavinm ++*nerrp; 640*20c794b3Sgavinm } 641*20c794b3Sgavinm } 642*20c794b3Sgavinm 643*20c794b3Sgavinm if (amd_dramchan_create(mod, mcnode, CHAN_NODE_NAME, auth) != 0 || 644*20c794b3Sgavinm amd_cs_create(mod, mcnode, CS_NODE_NAME, mc, auth) != 0 || 645*20c794b3Sgavinm amd_dimm_create(mod, mcnode, DIMM_NODE_NAME, mc, auth) != 0) 646*20c794b3Sgavinm ++*nerrp; 647*20c794b3Sgavinm 648*20c794b3Sgavinm /* 649*20c794b3Sgavinm * Free the fmris for the chip-selects allocated in amd_cs_create 650*20c794b3Sgavinm */ 651*20c794b3Sgavinm for (i = 0; i < MC_CHIP_NCS; i++) { 652*20c794b3Sgavinm if (cs_fmri[i] != NULL) { 653*20c794b3Sgavinm nvlist_free(cs_fmri[i]); 654*20c794b3Sgavinm cs_fmri[i] = NULL; 655*20c794b3Sgavinm } 656*20c794b3Sgavinm } 657*20c794b3Sgavinm 658*20c794b3Sgavinm nvlist_free(mc); 659*20c794b3Sgavinm } 660