1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2019, Joyent, Inc.
26 * Copyright 2020 Oxide Computer Company
27 */
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <alloca.h>
38 #include <kstat.h>
39 #include <errno.h>
40 #include <libnvpair.h>
41 #include <sys/types.h>
42 #include <sys/bitmap.h>
43 #include <sys/processor.h>
44 #include <sys/param.h>
45 #include <sys/fm/protocol.h>
46 #include <sys/systeminfo.h>
47 #include <sys/mc.h>
48 #include <sys/mc_amd.h>
49 #include <sys/mc_intel.h>
50 #include <sys/devfm.h>
51 #include <fm/fmd_agent.h>
52 #include <fm/topo_mod.h>
53
54 #include "chip.h"
55
56 #define MAX_DIMMNUM 7
57 #define MAX_CSNUM 7
58
59 /*
60 * Enumerates the processing chips, or sockets, (as distinct from cores) in a
61 * system. For each chip found, the necessary nodes (one or more cores, and
62 * possibly a memory controller) are constructed underneath.
63 */
64
65 static int chip_enum(topo_mod_t *, tnode_t *, const char *,
66 topo_instance_t, topo_instance_t, void *, void *);
67
68 static const topo_modops_t chip_ops =
69 { chip_enum, NULL};
70 static const topo_modinfo_t chip_info =
71 { CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
72
73 static const topo_pgroup_info_t chip_pgroup =
74 { PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
75
76 static const topo_pgroup_info_t core_pgroup =
77 { PGNAME(CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
78
79 static const topo_pgroup_info_t strand_pgroup =
80 { PGNAME(STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
81
82 static const topo_method_t chip_methods[] = {
83 { SIMPLE_CHIP_LBL, "Property method", 0,
84 TOPO_STABILITY_INTERNAL, simple_chip_label},
85 { G4_CHIP_LBL, "Property method", 0,
86 TOPO_STABILITY_INTERNAL, g4_chip_label},
87 { A4FPLUS_CHIP_LBL, "Property method", 0,
88 TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
89 { FSB2_CHIP_LBL, "Property method", 0,
90 TOPO_STABILITY_INTERNAL, fsb2_chip_label},
91 { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
92 TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
93 chip_fmri_replaced },
94 { NULL }
95 };
96
97 static const topo_method_t strands_retire_methods[] = {
98 { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
99 TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
100 retire_strands },
101 { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
102 TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
103 unretire_strands },
104 { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
105 TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
106 service_state_strands },
107 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
108 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
109 unusable_strands },
110 { NULL }
111 };
112
113 int
_topo_init(topo_mod_t * mod)114 _topo_init(topo_mod_t *mod)
115 {
116 if (getenv("TOPOCHIPDBG"))
117 topo_mod_setdebug(mod);
118 topo_mod_dprintf(mod, "initializing chip enumerator\n");
119
120 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
121 whinge(mod, NULL, "failed to register hc: "
122 "%s\n", topo_mod_errmsg(mod));
123 return (-1); /* mod errno set */
124 }
125
126 return (0);
127 }
128
129 void
_topo_fini(topo_mod_t * mod)130 _topo_fini(topo_mod_t *mod)
131 {
132 topo_mod_unregister(mod);
133 }
134
135 boolean_t
is_xpv(void)136 is_xpv(void)
137 {
138 static int r = -1;
139 char platform[MAXNAMELEN];
140
141 if (r != -1)
142 return (r == 0);
143
144 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
145 r = strcmp(platform, "i86xpv");
146 return (r == 0);
147 }
148
149 static tnode_t *
create_node(topo_mod_t * mod,tnode_t * pnode,nvlist_t * auth,char * name,topo_instance_t inst,nvlist_t * cpu,uint16_t smbios_id)150 create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name,
151 topo_instance_t inst, nvlist_t *cpu, uint16_t smbios_id)
152 {
153 nvlist_t *fmri;
154 tnode_t *cnode;
155
156 if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) {
157 whinge(mod, NULL, "create_node: mkrsrc failed\n");
158 return (NULL);
159 }
160
161 if (FM_AWARE_SMBIOS(mod)) {
162 id_t phys_cpu_smbid;
163 int perr = 0;
164 const char *serial = NULL;
165 const char *part = NULL;
166 const char *rev = NULL;
167
168 phys_cpu_smbid = smbios_id;
169 serial = chip_serial_smbios_get(mod, phys_cpu_smbid);
170 part = chip_part_smbios_get(mod, phys_cpu_smbid);
171 rev = chip_rev_smbios_get(mod, phys_cpu_smbid);
172
173 perr += nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
174 serial);
175 perr += nvlist_add_string(fmri, FM_FMRI_HC_PART,
176 part);
177 perr += nvlist_add_string(fmri, FM_FMRI_HC_REVISION,
178 rev);
179
180 if (perr != 0)
181 whinge(mod, NULL,
182 "create_node: nvlist_add_string failed\n");
183
184 topo_mod_strfree(mod, (char *)serial);
185 topo_mod_strfree(mod, (char *)part);
186 topo_mod_strfree(mod, (char *)rev);
187 } else {
188 char *serial = NULL;
189
190 if (nvlist_lookup_string(cpu, FM_PHYSCPU_INFO_CHIP_IDENTSTR,
191 &serial) == 0) {
192 if (nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
193 serial) != 0) {
194 whinge(mod, NULL,
195 "create_node: nvlist_add_string failed\n");
196 }
197 }
198 }
199
200 cnode = topo_node_bind(mod, pnode, name, inst, fmri);
201
202 nvlist_free(fmri);
203 if (cnode == NULL) {
204 whinge(mod, NULL, "create_node: node bind failed"
205 " for %s %d\n", name, (int)inst);
206 }
207
208 return (cnode);
209 }
210
211 static int
create_strand(topo_mod_t * mod,tnode_t * pnode,nvlist_t * cpu,nvlist_t * auth,uint16_t chip_smbiosid)212 create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
213 nvlist_t *auth, uint16_t chip_smbiosid)
214 {
215 tnode_t *strand;
216 int32_t strandid, cpuid;
217 int err, perr, nerr = 0;
218 nvlist_t *fmri;
219 char *serial = NULL;
220 char *part = NULL;
221 char *rev = NULL;
222
223 if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID,
224 &strandid)) != 0) {
225 whinge(mod, NULL, "create_strand: lookup strand_id failed: "
226 "%s\n", strerror(err));
227 return (-1);
228 }
229
230 if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid))
231 != NULL) {
232 whinge(mod, NULL, "create_strand: duplicate tuple found\n");
233 return (-1);
234 }
235
236 if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME,
237 strandid, cpu, chip_smbiosid)) == NULL)
238 return (-1);
239
240 /*
241 * Inherit FRU from core node, in native use cpu scheme ASRU,
242 * in xpv, use hc scheme ASRU.
243 */
244 (void) topo_node_fru_set(strand, NULL, 0, &perr);
245 /*
246 * From the inherited FRU, extract the Serial
247 * number(if SMBIOS donates) and set it in the ASRU
248 */
249 if (FM_AWARE_SMBIOS(mod)) {
250 char *val = NULL;
251
252 if (topo_prop_get_fmri(strand, TOPO_PGROUP_PROTOCOL,
253 TOPO_PROP_RESOURCE, &fmri, &err) != 0)
254 whinge(mod, NULL,
255 "create_strand: topo_prop_get_fmri failed\n");
256 if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID, &val) != 0)
257 whinge(mod, NULL,
258 "create_strand: nvlist_lookup_string failed: \n");
259 else
260 serial = topo_mod_strdup(mod, val);
261 nvlist_free(fmri);
262 }
263 if (is_xpv()) {
264 if (topo_node_resource(strand, &fmri, &err) == -1) {
265 whinge(mod, &nerr, "create_strand: "
266 "topo_node_resource failed\n");
267 } else {
268 if (FM_AWARE_SMBIOS(mod))
269 (void) nvlist_add_string(fmri,
270 FM_FMRI_HC_SERIAL_ID, serial);
271 (void) topo_node_asru_set(strand, fmri, 0, &err);
272 nvlist_free(fmri);
273 }
274 } else {
275 if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
276 whinge(mod, &nerr, "create_strand: lookup cpuid "
277 "failed\n");
278 } else {
279 if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
280 != NULL) {
281 (void) topo_node_asru_set(strand, fmri,
282 0, &err);
283 nvlist_free(fmri);
284 } else {
285 whinge(mod, &nerr, "create_strand: "
286 "cpu_fmri_create() failed\n");
287 }
288 }
289 }
290
291 if (topo_method_register(mod, strand, strands_retire_methods) < 0)
292 whinge(mod, &nerr, "create_strand: "
293 "topo_method_register failed\n");
294
295 (void) topo_pgroup_create(strand, &strand_pgroup, &err);
296 nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL,
297 STRAND_CHIP_ID, STRAND_PROCNODE_ID, STRAND_CORE_ID, STRAND_CPU_ID,
298 NULL);
299
300 if (FM_AWARE_SMBIOS(mod)) {
301 (void) topo_node_label_set(strand, NULL, &perr);
302
303 if (topo_node_resource(strand, &fmri, &perr) != 0) {
304 whinge(mod, &nerr, "create_strand: "
305 "topo_node_resource failed\n");
306 perr = 0;
307 }
308
309 perr += nvlist_lookup_string(fmri,
310 FM_FMRI_HC_PART, &part);
311 perr += nvlist_lookup_string(fmri,
312 FM_FMRI_HC_REVISION, &rev);
313
314 if (perr != 0) {
315 whinge(mod, NULL,
316 "create_strand: nvlist_lookup_string failed\n");
317 perr = 0;
318 }
319
320 perr += topo_prop_set_string(strand, PGNAME(STRAND),
321 FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
322 perr += topo_prop_set_string(strand, PGNAME(STRAND),
323 FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
324 perr += topo_prop_set_string(strand, PGNAME(STRAND),
325 FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
326
327 if (perr != 0)
328 whinge(mod, NULL, "create_strand: topo_prop_set_string"
329 "failed\n");
330
331 nvlist_free(fmri);
332 topo_mod_strfree(mod, serial);
333 }
334
335 return (err == 0 && nerr == 0 ? 0 : -1);
336 }
337
338 static int
create_core(topo_mod_t * mod,tnode_t * pnode,nvlist_t * cpu,nvlist_t * auth,uint16_t chip_smbiosid)339 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
340 nvlist_t *auth, uint16_t chip_smbiosid)
341 {
342 tnode_t *core;
343 int32_t coreid, cpuid;
344 int err, perr, nerr = 0;
345 nvlist_t *fmri;
346 char *serial = NULL;
347 char *part = NULL;
348 char *rev = NULL;
349
350 if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
351 != 0) {
352 whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
353 strerror(err));
354 return (-1);
355 }
356 if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
357 if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
358 coreid, cpu, chip_smbiosid)) == NULL)
359 return (-1);
360
361 /*
362 * Inherit FRU from the chip node, for native, we use hc
363 * scheme ASRU for the core node.
364 */
365 (void) topo_node_fru_set(core, NULL, 0, &perr);
366 /*
367 * From the inherited FRU, extract the Serial
368 * number if SMBIOS donates and set it in the ASRU
369 */
370 if (FM_AWARE_SMBIOS(mod)) {
371 char *val = NULL;
372
373 if (topo_node_resource(core, &fmri, &err) != 0)
374 whinge(mod, NULL,
375 "create_core: topo_prop_get_fmri failed\n");
376 if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID,
377 &val) != 0)
378 whinge(mod, NULL, "create_core:"
379 "nvlist_lookup_string failed\n");
380 else
381 serial = topo_mod_strdup(mod, val);
382 nvlist_free(fmri);
383 }
384 if (is_xpv()) {
385 if (topo_node_resource(core, &fmri, &err) == -1) {
386 whinge(mod, &nerr, "create_core: "
387 "topo_node_resource failed\n");
388 } else {
389 if (FM_AWARE_SMBIOS(mod))
390 (void) nvlist_add_string(fmri,
391 FM_FMRI_HC_SERIAL_ID, serial);
392 (void) topo_node_asru_set(core, fmri, 0, &err);
393 nvlist_free(fmri);
394 }
395 }
396 if (topo_method_register(mod, core, strands_retire_methods) < 0)
397 whinge(mod, &nerr, "create_core: "
398 "topo_method_register failed\n");
399
400 (void) topo_pgroup_create(core, &core_pgroup, &err);
401 nerr -= add_nvlist_longprops(mod, core, cpu, PGNAME(CORE), NULL,
402 CORE_CHIP_ID, CORE_PROCNODE_ID, NULL);
403
404 if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
405 0, 255) != 0)
406 return (-1);
407
408 /*
409 * Creating a temperature sensor may fail because the sensor
410 * doesn't exist or due to internal reasons. At the moment, we
411 * swallow any such errors that occur.
412 */
413 (void) chip_create_core_temp_sensor(mod, core);
414 }
415
416 if (!is_xpv()) {
417 /*
418 * In native mode, we're in favor of cpu scheme ASRU for
419 * printing reason. More work needs to be done to support
420 * multi-strand cpu: the ASRU will be a list of cpuid then.
421 */
422 if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
423 whinge(mod, &nerr, "create_core: lookup cpuid "
424 "failed\n");
425 } else {
426 if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
427 != NULL) {
428 (void) topo_node_asru_set(core, fmri, 0, &err);
429 nvlist_free(fmri);
430 } else {
431 whinge(mod, &nerr, "create_core: "
432 "cpu_fmri_create() failed\n");
433 }
434 }
435 }
436
437 if (FM_AWARE_SMBIOS(mod)) {
438 (void) topo_node_label_set(core, NULL, &perr);
439
440 if (topo_node_resource(core, &fmri, &perr) != 0) {
441 whinge(mod, &nerr, "create_core: "
442 "topo_node_resource failed\n");
443 perr = 0;
444 }
445
446 perr += nvlist_lookup_string(fmri,
447 FM_FMRI_HC_PART, &part);
448 perr += nvlist_lookup_string(fmri,
449 FM_FMRI_HC_REVISION, &rev);
450
451 if (perr != 0) {
452 whinge(mod, NULL,
453 "create_core: nvlist_lookup_string failed\n");
454 perr = 0;
455 }
456
457 perr += topo_prop_set_string(core, PGNAME(CORE),
458 FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
459 perr += topo_prop_set_string(core, PGNAME(CORE),
460 FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
461 perr += topo_prop_set_string(core, PGNAME(CORE),
462 FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
463
464 if (perr != 0)
465 whinge(mod, NULL, "create_core: topo_prop_set_string"
466 "failed\n");
467
468 nvlist_free(fmri);
469 topo_mod_strfree(mod, serial);
470 }
471
472 err = create_strand(mod, core, cpu, auth, chip_smbiosid);
473
474 return (err == 0 && nerr == 0 ? 0 : -1);
475 }
476
477 static int
create_chip(topo_mod_t * mod,tnode_t * pnode,topo_instance_t min,topo_instance_t max,nvlist_t * cpu,nvlist_t * auth,int mc_offchip,kstat_ctl_t * kc)478 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
479 topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
480 int mc_offchip, kstat_ctl_t *kc)
481 {
482 tnode_t *chip;
483 nvlist_t *fmri = NULL;
484 int err, perr, nerr = 0;
485 int32_t chipid, procnodeid, procnodes_per_pkg;
486 const char *vendor;
487 char *brand, *socket;
488 int32_t family, model;
489 boolean_t create_mc = B_FALSE;
490 uint16_t smbios_id;
491
492 /*
493 * /dev/fm will export the chipid based on SMBIOS' ordering
494 * of Type-4 structures, if SMBIOS meets FMA needs
495 */
496 err = nvlist_lookup_pairs(cpu, 0,
497 FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, &chipid,
498 FM_PHYSCPU_INFO_NPROCNODES, DATA_TYPE_INT32, &procnodes_per_pkg,
499 FM_PHYSCPU_INFO_PROCNODE_ID, DATA_TYPE_INT32, &procnodeid,
500 FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, &vendor,
501 FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, &family,
502 FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, &model,
503 NULL);
504
505 if (err) {
506 whinge(mod, NULL, "create_chip: lookup failed: %s\n",
507 strerror(err));
508 return (-1);
509 }
510
511 if (chipid < min || chipid > max)
512 return (-1);
513
514 if (FM_AWARE_SMBIOS(mod)) {
515 if ((err = nvlist_lookup_uint16(cpu,
516 FM_PHYSCPU_INFO_SMBIOS_ID, &smbios_id)) != 0) {
517 whinge(mod, NULL,
518 "create_chip: lookup smbios_id failed"
519 ": enumerating x86pi & chip topology, but"
520 " no Chip properties from SMBIOS"
521 " - err msg : %s\n", strerror(err));
522 /*
523 * Lets reset the module specific
524 * data to NULL, overriding any
525 * SMBIOS capability encoded earlier.
526 * This will fail all subsequent
527 * FM_AWARE_SMBIOS checks.
528 */
529 topo_mod_setspecific(mod, NULL);
530 }
531 }
532
533 if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
534 if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
535 chipid, cpu, smbios_id)) == NULL)
536 return (-1);
537 /*
538 * Do not register XML map methods if SMBIOS can provide
539 * serial, part, revision & label
540 */
541 if (!FM_AWARE_SMBIOS(mod)) {
542 if (topo_method_register(mod, chip, chip_methods) < 0)
543 whinge(mod, &nerr, "create_chip: "
544 "topo_method_register failed\n");
545 }
546
547 (void) topo_pgroup_create(chip, &chip_pgroup, &err);
548 nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
549 CHIP_VENDOR_ID, NULL);
550 nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
551 NULL, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
552
553 /*
554 * Attempt to lookup the processor brand and socket string in
555 * kstats and add it as a prop, if found.
556 */
557 brand = socket = NULL;
558 get_chip_kstat_strs(mod, kc, chipid, &brand, &socket);
559 if (brand != NULL && topo_prop_set_string(chip, PGNAME(CHIP),
560 CHIP_BRAND, TOPO_PROP_IMMUTABLE, brand, &perr) != 0) {
561 whinge(mod, &nerr, "failed to set prop %s/%s",
562 PGNAME(CHIP), CHIP_BRAND);
563 }
564 topo_mod_strfree(mod, brand);
565
566 if (socket != NULL && topo_prop_set_string(chip, PGNAME(CHIP),
567 CHIP_SOCKET, TOPO_PROP_IMMUTABLE, socket, &perr) != 0) {
568 whinge(mod, &nerr, "failed to set prop %s/%s",
569 PGNAME(CHIP), CHIP_SOCKET);
570 }
571 topo_mod_strfree(mod, socket);
572
573 if (FM_AWARE_SMBIOS(mod)) {
574 int fru = 0;
575 char *serial = NULL;
576 char *part = NULL;
577 char *rev = NULL;
578 char *label;
579
580 fru = chip_fru_smbios_get(mod, smbios_id);
581 /*
582 * Chip is not a FRU, set the FRU fmri of parent node
583 */
584 if (topo_node_resource(chip, &fmri, &perr) != 0)
585 whinge(mod, &nerr, "create_chip: "
586 "topo_node_resource failed\n");
587 if (!fru) {
588 (void) topo_node_fru_set(chip, NULL, 0, &perr);
589 label = NULL;
590 } else {
591 label = (char *)chip_label_smbios_get(mod,
592 pnode, smbios_id, NULL);
593
594 if (topo_node_fru_set(chip, fmri, 0, &perr)
595 != 0) {
596 whinge(mod, NULL, "create_chip: "
597 "topo_node_fru_set failed\n");
598 perr = 0;
599 }
600 }
601
602 perr += nvlist_lookup_string(fmri,
603 FM_FMRI_HC_SERIAL_ID, &serial);
604 perr += nvlist_lookup_string(fmri,
605 FM_FMRI_HC_PART, &part);
606 perr += nvlist_lookup_string(fmri,
607 FM_FMRI_HC_REVISION, &rev);
608
609 if (perr != 0) {
610 whinge(mod, NULL,
611 "create_chip: nvlist_lookup_string"
612 "failed\n");
613 perr = 0;
614 }
615
616 perr += topo_prop_set_string(chip, PGNAME(CHIP),
617 FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
618 serial, &perr);
619 perr += topo_prop_set_string(chip, PGNAME(CHIP),
620 FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
621 part, &perr);
622 perr += topo_prop_set_string(chip, PGNAME(CHIP),
623 FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
624 rev, &perr);
625
626 if (perr != 0)
627 whinge(mod, NULL,
628 "create_chip: topo_prop_set_string"
629 "failed\n");
630
631 nvlist_free(fmri);
632
633 if (topo_node_label_set(chip, label, &perr)
634 == -1) {
635 whinge(mod, NULL, "create_chip: "
636 "topo_node_label_set failed\n");
637 }
638 topo_mod_strfree(mod, label);
639
640 } else {
641 if (topo_node_resource(chip, &fmri, &err) == -1) {
642 whinge(mod, &nerr, "create_chip: "
643 "topo_node_resource failed\n");
644 } else {
645 (void) topo_node_fru_set(chip, fmri, 0, &perr);
646 nvlist_free(fmri);
647 }
648 }
649
650 if (topo_method_register(mod, chip, strands_retire_methods) < 0)
651 whinge(mod, &nerr, "create_chip: "
652 "topo_method_register failed\n");
653
654 if (topo_node_range_create(mod, chip, CORE_NODE_NAME, 0, 255))
655 return (-1);
656
657 if (strcmp(vendor, "AuthenticAMD") == 0) {
658 if (topo_node_range_create(mod, chip, MCT_NODE_NAME,
659 0, 255))
660 return (-1);
661 }
662
663 create_mc = B_TRUE;
664
665 /*
666 * Creating a temperature sensor may fail because the sensor
667 * doesn't exist or due to internal reasons. At the moment, we
668 * swallow any such errors that occur.
669 */
670 (void) chip_create_chip_temp_sensor(mod, chip);
671 }
672
673 if (FM_AWARE_SMBIOS(mod)) {
674 int status = 0;
675 /*
676 * STATUS
677 * CPU Socket Populated
678 * CPU Socket Unpopulated
679 * Populated : Enabled
680 * Populated : Disabled by BIOS (Setup)
681 * Populated : Disabled by BIOS (Error)
682 * Populated : Idle
683 *
684 * Enumerate core & strand only for Populated : Enabled
685 * Enumerate Off-Chip Memory Controller only for
686 * Populated : Enabled
687 */
688
689 status = chip_status_smbios_get(mod, (id_t)smbios_id);
690 if (!status) {
691 whinge(mod, NULL, "create_chip: "
692 "CPU Socket is not populated or is disabled\n");
693 return (0);
694 }
695 }
696
697 err = create_core(mod, chip, cpu, auth, smbios_id);
698
699 /*
700 * Create memory-controller node under a chip for architectures
701 * that may have on-chip memory-controller(s).
702 * If SMBIOS meets FMA needs, when Multi-Chip-Module is
703 * addressed, mc instances should be derived from SMBIOS
704 */
705 if (strcmp(vendor, "AuthenticAMD") == 0) {
706 amd_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth,
707 procnodeid, procnodes_per_pkg, family, model, &nerr);
708 } else if (create_mc && !mc_offchip)
709 onchip_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth);
710
711 return (err == 0 && nerr == 0 ? 0 : -1);
712 }
713
714 /*ARGSUSED*/
715 static int
create_chips(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,nvlist_t * auth,int mc_offchip)716 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
717 topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
718 int mc_offchip)
719 {
720 fmd_agent_hdl_t *hdl;
721 nvlist_t **cpus;
722 int nerr = 0;
723 uint_t i, ncpu;
724 kstat_ctl_t *kc;
725
726 if (strcmp(name, CHIP_NODE_NAME) != 0)
727 return (0);
728
729 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
730 return (-1);
731 if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
732 whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
733 "failed: %s\n", fmd_agent_errmsg(hdl));
734 fmd_agent_close(hdl);
735 return (-1);
736 }
737 fmd_agent_close(hdl);
738
739 if ((kc = kstat_open()) == NULL) {
740 whinge(mod, NULL, "kstat_open() failed");
741 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
742 }
743
744 for (i = 0; i < ncpu; i++) {
745 nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
746 mc_offchip, kc);
747 nvlist_free(cpus[i]);
748 }
749 (void) kstat_close(kc);
750 umem_free(cpus, sizeof (nvlist_t *) * ncpu);
751
752 if (nerr == 0) {
753 return (0);
754 } else {
755 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
756 return (-1);
757 }
758 }
759
760 /*ARGSUSED*/
761 static int
chip_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * smbios_enabled)762 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
763 topo_instance_t min, topo_instance_t max, void *arg, void *smbios_enabled)
764 {
765 int rv = 0;
766 nvlist_t *auth = NULL;
767 int offchip_mc;
768 char buf[BUFSIZ];
769 const char *dom0 = "control_d";
770
771 /*
772 * Create nothing if we're running in domU.
773 */
774 if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
775 return (-1);
776
777 if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
778 strncmp(buf, "i86xpv", sizeof (buf)) != 0)
779 return (0);
780
781 if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
782 int fd = open("/dev/xen/domcaps", O_RDONLY);
783
784 if (fd != -1) {
785 if (read(fd, buf, sizeof (buf)) <= 0 ||
786 strncmp(buf, dom0, strlen(dom0)) != 0) {
787 (void) close(fd);
788 return (0);
789 }
790 (void) close(fd);
791 }
792 }
793
794 /*
795 * Set Chip Enumerator Module's private data with the value passed by
796 * x86pi Enumerator, defining SMBIOS capabilities
797 */
798 topo_mod_setspecific(mod, smbios_enabled);
799
800 if (FM_AWARE_SMBIOS(mod))
801 if (init_chip_smbios(mod) != 0) {
802 whinge(mod, NULL,
803 "init_chip_smbios() failed, "
804 " enumerating x86pi & chip topology, but no"
805 " CPU & Memory properties will be"
806 " derived from SMBIOS\n");
807 /*
808 * Lets reset the module specific
809 * data to NULL, overriding any
810 * SMBIOS capability encoded earlier.
811 * This will fail all subsequent
812 * FM_AWARE_SMBIOS checks.
813 */
814 topo_mod_setspecific(mod, NULL);
815 }
816
817 auth = topo_mod_auth(mod, pnode);
818
819 offchip_mc = mc_offchip_open();
820 if (strcmp(name, CHIP_NODE_NAME) == 0)
821 rv = create_chips(mod, pnode, name, min, max, NULL, auth,
822 offchip_mc);
823
824 if (offchip_mc)
825 (void) mc_offchip_create(mod, pnode, "memory-controller", auth);
826
827 nvlist_free(auth);
828
829 return (rv);
830 }
831