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 /*
23efd31e1dSTrang 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
amd_generic_mc_create(topo_mod_t * mod,uint16_t smbid,tnode_t * cnode,tnode_t * mcnode,int family,int model,nvlist_t * auth)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
14721ad40f5SJens Elkner * for revisions A to E of family 0x10 (for the list of models
148b8201470SSrihari Venkatesan * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c).
14921ad40f5SJens Elkner * We cover all family 0x10 models, till model 10.
15020c794b3Sgavinm */
15121ad40f5SJens Elkner if (family > 0x10 || (family == 0x10 && model > 10))
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;
267efd31e1dSTrang 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 *
amd_lookup_by_mcid(topo_mod_t * mod,topo_instance_t id)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
amd_rank_create(topo_mod_t * mod,tnode_t * pnode,nvlist_t * dimmnvl,nvlist_t * auth)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
amd_dimm_create(topo_mod_t * mod,uint16_t chip_smbid,tnode_t * pnode,const char * name,nvlist_t * mc,nvlist_t * auth)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;
470*58d4b16fSRobert Mustacchi id_t smbid = -1;
471*58d4b16fSRobert Mustacchi const char *serial = NULL;
472*58d4b16fSRobert Mustacchi const char *part = NULL;
473*58d4b16fSRobert Mustacchi const char *rev = NULL;
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)) {
500efd31e1dSTrang Do smbid = memnode_to_smbiosid(mod, chip_smbid,
501efd31e1dSTrang 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)) {
565*58d4b16fSRobert Mustacchi if ((nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY &&
566*58d4b16fSRobert Mustacchi strcmp(nvpair_name(nvp), "csnums") == 0) ||
567*58d4b16fSRobert Mustacchi (nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY &&
568*58d4b16fSRobert Mustacchi 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
amd_cs_create(topo_mod_t * mod,tnode_t * pnode,const char * name,nvlist_t * mc,nvlist_t * auth)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
amd_dramchan_create(topo_mod_t * mod,tnode_t * pnode,const char * name,nvlist_t * auth)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 }
691aab83bb8SJosef 'Jeff' Sipek nvlist_free(pfmri);
69220c794b3Sgavinm
69320c794b3Sgavinm return (nerr == 0 ? 0 : -1);
69420c794b3Sgavinm }
69520c794b3Sgavinm
69620c794b3Sgavinm static int
amd_htconfig(topo_mod_t * mod,tnode_t * cnode,nvlist_t * htnvl)69720c794b3Sgavinm amd_htconfig(topo_mod_t *mod, tnode_t *cnode, nvlist_t *htnvl)
69820c794b3Sgavinm {
69920c794b3Sgavinm nvpair_t *nvp;
70020c794b3Sgavinm int nerr = 0;
70120c794b3Sgavinm
70220c794b3Sgavinm if (strcmp(topo_node_name(cnode), CHIP_NODE_NAME) != 0) {
70320c794b3Sgavinm whinge(mod, &nerr, "amd_htconfig: must pass a chip node!");
70420c794b3Sgavinm return (-1);
70520c794b3Sgavinm }
70620c794b3Sgavinm
70720c794b3Sgavinm for (nvp = nvlist_next_nvpair(htnvl, NULL); nvp != NULL;
70820c794b3Sgavinm nvp = nvlist_next_nvpair(htnvl, nvp)) {
70920c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(CHIP), cnode) != 0)
71020c794b3Sgavinm nerr++;
71120c794b3Sgavinm }
71220c794b3Sgavinm
71320c794b3Sgavinm return (nerr == 0 ? 0 : -1);
71420c794b3Sgavinm }
71520c794b3Sgavinm
71620c794b3Sgavinm void
amd_mc_create(topo_mod_t * mod,uint16_t smbid,tnode_t * pnode,const char * name,nvlist_t * auth,int32_t procnodeid,int32_t procnodes_per_pkg,int family,int model,int * nerrp)7178031591dSSrihari Venkatesan amd_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *pnode,
7188031591dSSrihari Venkatesan const char *name, nvlist_t *auth, int32_t procnodeid,
7198031591dSSrihari Venkatesan int32_t procnodes_per_pkg, int family,
7208031591dSSrihari Venkatesan int model, int *nerrp)
72120c794b3Sgavinm {
72220c794b3Sgavinm tnode_t *mcnode;
7235895e34bSSrihari Venkatesan nvlist_t *rfmri, *fmri;
72420c794b3Sgavinm nvpair_t *nvp;
72520c794b3Sgavinm nvlist_t *mc = NULL;
7261db96d3bSCheng Sean Ye int i, err;
7278031591dSSrihari Venkatesan int mcnum = procnodeid % procnodes_per_pkg;
728074bb90dSTom Pothier char *serial = NULL;
729074bb90dSTom Pothier char *part = NULL;
730074bb90dSTom Pothier char *rev = NULL;
73120c794b3Sgavinm
73220c794b3Sgavinm /*
73320c794b3Sgavinm * Return with no error for anything before AMD family 0xf - we
7348031591dSSrihari Venkatesan * won't generate even a generic memory topology for earlier
73520c794b3Sgavinm * families.
73620c794b3Sgavinm */
73720c794b3Sgavinm if (family < 0xf)
73820c794b3Sgavinm return;
73920c794b3Sgavinm
7408031591dSSrihari Venkatesan if (topo_node_lookup(pnode, name, mcnum) != NULL)
7418031591dSSrihari Venkatesan return;
7428031591dSSrihari Venkatesan
743074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) {
7445895e34bSSrihari Venkatesan (void) topo_node_resource(pnode, &rfmri, &err);
7455895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "serial", &serial);
7465895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "part", &part);
7475895e34bSSrihari Venkatesan (void) nvlist_lookup_string(rfmri, "revision", &rev);
748074bb90dSTom Pothier }
749074bb90dSTom Pothier
7508031591dSSrihari Venkatesan if (mkrsrc(mod, pnode, name, mcnum, auth, &fmri) != 0) {
7515895e34bSSrihari Venkatesan if (FM_AWARE_SMBIOS(mod))
7525895e34bSSrihari Venkatesan nvlist_free(rfmri);
75320c794b3Sgavinm whinge(mod, nerrp, "mc_create: mkrsrc failed\n");
75420c794b3Sgavinm return;
75520c794b3Sgavinm }
75620c794b3Sgavinm
757074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) {
758074bb90dSTom Pothier (void) nvlist_add_string(fmri, "serial", serial);
759074bb90dSTom Pothier (void) nvlist_add_string(fmri, "part", part);
760074bb90dSTom Pothier (void) nvlist_add_string(fmri, "revision", rev);
7615895e34bSSrihari Venkatesan nvlist_free(rfmri);
762074bb90dSTom Pothier }
763074bb90dSTom Pothier
7648031591dSSrihari Venkatesan if ((mcnode = topo_node_bind(mod, pnode, name, mcnum,
76520c794b3Sgavinm fmri)) == NULL) {
76620c794b3Sgavinm nvlist_free(fmri);
76720c794b3Sgavinm whinge(mod, nerrp, "mc_create: mc bind failed\n");
76820c794b3Sgavinm return;
76920c794b3Sgavinm }
7701db96d3bSCheng Sean Ye if (topo_node_fru_set(mcnode, NULL, 0, &err) < 0)
7711db96d3bSCheng Sean Ye whinge(mod, nerrp, "mc_create: topo_node_fru_set failed\n");
7721db96d3bSCheng Sean Ye
773074bb90dSTom Pothier if (FM_AWARE_SMBIOS(mod)) {
774074bb90dSTom Pothier if (topo_node_label_set(mcnode, NULL, &err) == -1)
775074bb90dSTom Pothier topo_mod_dprintf(mod, "Failed to set label\n");
776074bb90dSTom Pothier }
777074bb90dSTom Pothier
77820c794b3Sgavinm nvlist_free(fmri);
77920c794b3Sgavinm
7808031591dSSrihari Venkatesan if (topo_pgroup_create(mcnode, &mc_pgroup, &err) < 0)
7818031591dSSrihari Venkatesan whinge(mod, nerrp, "mc_create: topo_pgroup_create failed\n");
7828031591dSSrihari Venkatesan
7838031591dSSrihari Venkatesan if (topo_prop_set_int32(mcnode, PGNAME(MCT), MCT_PROCNODE_ID,
7848031591dSSrihari Venkatesan TOPO_PROP_IMMUTABLE, procnodeid, nerrp) != 0)
7858031591dSSrihari Venkatesan whinge(mod, nerrp, "mc_create: topo_prop_set_int32 failed to"
7868031591dSSrihari Venkatesan "add node id\n");
7878031591dSSrihari Venkatesan
78820c794b3Sgavinm if ((mc = amd_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL) {
78920c794b3Sgavinm /*
79020c794b3Sgavinm * If a memory-controller driver exists for this chip model
79120c794b3Sgavinm * it has not attached or has otherwise malfunctioned;
79220c794b3Sgavinm * alternatively no memory-controller driver exists for this
79320c794b3Sgavinm * (presumably newly-released) cpu model. We fallback to
79420c794b3Sgavinm * creating a generic maximal topology.
79520c794b3Sgavinm */
796074bb90dSTom Pothier if (amd_generic_mc_create(mod, smbid, pnode, mcnode,
7978031591dSSrihari Venkatesan family, model, auth) != 0)
7981db96d3bSCheng Sean Ye whinge(mod, nerrp,
7991db96d3bSCheng Sean Ye "mc_create: amd_generic_mc_create failed\n");
80020c794b3Sgavinm return;
80120c794b3Sgavinm }
80220c794b3Sgavinm
80320c794b3Sgavinm /*
80420c794b3Sgavinm * Add memory controller properties
80520c794b3Sgavinm */
80620c794b3Sgavinm for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL;
80720c794b3Sgavinm nvp = nvlist_next_nvpair(mc, nvp)) {
80820c794b3Sgavinm char *name = nvpair_name(nvp);
80920c794b3Sgavinm data_type_t type = nvpair_type(nvp);
81020c794b3Sgavinm
81120c794b3Sgavinm if (type == DATA_TYPE_NVLIST_ARRAY &&
81220c794b3Sgavinm (strcmp(name, "cslist") == 0 ||
81320c794b3Sgavinm strcmp(name, "dimmlist") == 0)) {
81420c794b3Sgavinm continue;
81520c794b3Sgavinm } else if (type == DATA_TYPE_UINT8 &&
81620c794b3Sgavinm strcmp(name, MC_NVLIST_VERSTR) == 0) {
81720c794b3Sgavinm continue;
81820c794b3Sgavinm } else if (type == DATA_TYPE_NVLIST &&
81920c794b3Sgavinm strcmp(name, "htconfig") == 0) {
82020c794b3Sgavinm nvlist_t *htnvl;
82120c794b3Sgavinm
82220c794b3Sgavinm (void) nvpair_value_nvlist(nvp, &htnvl);
82320c794b3Sgavinm if (amd_htconfig(mod, pnode, htnvl) != 0)
8241db96d3bSCheng Sean Ye whinge(mod, nerrp,
8251db96d3bSCheng Sean Ye "mc_create: amd_htconfig failed\n");
82620c794b3Sgavinm } else {
82720c794b3Sgavinm if (nvprop_add(mod, nvp, PGNAME(MCT), mcnode) != 0)
8281db96d3bSCheng Sean Ye whinge(mod, nerrp,
8291db96d3bSCheng Sean Ye "mc_create: nvprop_add failed\n");
83020c794b3Sgavinm }
83120c794b3Sgavinm }
83220c794b3Sgavinm
83320c794b3Sgavinm if (amd_dramchan_create(mod, mcnode, CHAN_NODE_NAME, auth) != 0 ||
83420c794b3Sgavinm amd_cs_create(mod, mcnode, CS_NODE_NAME, mc, auth) != 0 ||
835074bb90dSTom Pothier amd_dimm_create(mod, smbid, mcnode, DIMM_NODE_NAME, mc, auth) != 0)
8361db96d3bSCheng Sean Ye whinge(mod, nerrp, "mc_create: create children failed\n");
83720c794b3Sgavinm
83820c794b3Sgavinm /*
83920c794b3Sgavinm * Free the fmris for the chip-selects allocated in amd_cs_create
84020c794b3Sgavinm */
84120c794b3Sgavinm for (i = 0; i < MC_CHIP_NCS; i++) {
84220c794b3Sgavinm if (cs_fmri[i] != NULL) {
84320c794b3Sgavinm nvlist_free(cs_fmri[i]);
84420c794b3Sgavinm cs_fmri[i] = NULL;
84520c794b3Sgavinm }
84620c794b3Sgavinm }
84720c794b3Sgavinm
84820c794b3Sgavinm nvlist_free(mc);
84920c794b3Sgavinm }
850