Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c
+++ new/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * AMD memory enumeration
28 28 */
29 29
30 30 #include <sys/types.h>
31 31 #include <unistd.h>
32 32 #include <stropts.h>
33 33 #include <sys/fm/protocol.h>
34 34 #include <sys/mc.h>
35 35 #include <sys/mc_amd.h>
36 36 #include <fm/topo_mod.h>
37 37 #include <strings.h>
38 38 #include <sys/stat.h>
39 39 #include <fcntl.h>
40 40
41 41 #include "chip.h"
42 42
43 43 #define MAX_CHANNUM 1
44 44 #define MAX_DIMMNUM 7
45 45 #define MAX_CSNUM 7
46 46
47 47 static const topo_pgroup_info_t cs_pgroup =
48 48 { PGNAME(CS), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
49 49 static const topo_pgroup_info_t dimm_pgroup =
50 50 { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
51 51 static const topo_pgroup_info_t mc_pgroup =
52 52 { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
53 53 static const topo_pgroup_info_t rank_pgroup =
54 54 { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
55 55 static const topo_pgroup_info_t chan_pgroup =
56 56 { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
57 57
58 58 static const topo_method_t dimm_methods[] = {
59 59 { SIMPLE_DIMM_LBL, "Property method", 0,
60 60 TOPO_STABILITY_INTERNAL, simple_dimm_label},
61 61 { SIMPLE_DIMM_LBL_MP, "Property method", 0,
62 62 TOPO_STABILITY_INTERNAL, simple_dimm_label_mp},
63 63 { SEQ_DIMM_LBL, "Property method", 0,
64 64 TOPO_STABILITY_INTERNAL, seq_dimm_label},
65 65 { G4_DIMM_LBL, "Property method", 0,
66 66 TOPO_STABILITY_INTERNAL, g4_dimm_label},
67 67 { G12F_DIMM_LBL, "Property method", 0,
68 68 TOPO_STABILITY_INTERNAL, g12f_dimm_label},
69 69 { GET_DIMM_SERIAL, "Property method", 0,
70 70 TOPO_STABILITY_INTERNAL, get_dimm_serial},
71 71 { NULL }
72 72 };
73 73
74 74 const topo_method_t rank_methods[] = {
75 75 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
76 76 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
77 77 mem_asru_compute },
78 78 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC,
79 79 TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL,
80 80 rank_fmri_present },
81 81 { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
82 82 TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
83 83 rank_fmri_replaced },
84 84 { NULL }
85 85 };
86 86
87 87 const topo_method_t ntv_page_retire_methods[] = {
88 88 { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
89 89 TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
90 90 ntv_page_retire },
91 91 { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
92 92 TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
93 93 ntv_page_unretire },
94 94 { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
95 95 TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
96 96 ntv_page_service_state },
97 97 { NULL }
98 98 };
99 99
100 100 /*
101 101 * Serials, Labels are obtained from SMBIOS, so
102 102 * we leave out the related methods, any other
103 103 * methods that will be added to gen_cs_methods
104 104 * should be added to x86pi_gen_cs_methods too
105 105 */
106 106 static const topo_method_t x86pi_gen_cs_methods[] = {
107 107 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
108 108 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
109 109 mem_asru_compute },
110 110 { NULL }
111 111 };
112 112
113 113 static const topo_method_t gen_cs_methods[] = {
114 114 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
115 115 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
116 116 mem_asru_compute },
117 117 { SIMPLE_CS_LBL_MP, "Property method", 0,
118 118 TOPO_STABILITY_INTERNAL, simple_cs_label_mp},
119 119 { GET_DIMM_SERIAL, "Property method", 0,
120 120 TOPO_STABILITY_INTERNAL, get_dimm_serial},
121 121 { NULL }
122 122 };
123 123
124 124 static nvlist_t *cs_fmri[MC_CHIP_NCS];
125 125
126 126 /*
127 127 * Called when there is no memory-controller driver to provide topology
128 128 * information. Generate a maximal memory topology that is appropriate
129 129 * for the chip revision. The memory-controller node has already been
130 130 * bound as mcnode, and the parent of that is cnode.
131 131 *
132 132 * We create a tree of dram-channel and chip-select nodes below the
133 133 * memory-controller node. There will be two dram channels and 8 chip-selects
134 134 * below each, regardless of actual socket type, processor revision and so on.
135 135 * This is adequate for generic diagnosis up to family 0x10 revision D.
136 136 */
137 137 /*ARGSUSED*/
138 138 static int
139 139 amd_generic_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *cnode,
140 140 tnode_t *mcnode, int family, int model, nvlist_t *auth)
141 141 {
142 142 int chan, cs;
143 143
144 144 /*
145 145 * Elsewhere we have already returned for families less than 0xf.
146 146 * This "generic" topology is adequate for all of family 0xf and
147 147 * for revisions A to E of family 0x10 (for the list of models
148 148 * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c).
149 149 * We cover all family 0x10 models, till model 10.
150 150 */
151 151 if (family > 0x10 || (family == 0x10 && model > 10))
152 152 return (1);
153 153
154 154 if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0,
155 155 MAX_CHANNUM) < 0) {
156 156 whinge(mod, NULL, "amd_generic_mc_create: range create for "
157 157 "channels failed\n");
158 158 return (-1);
159 159 }
160 160
161 161 for (chan = 0; chan <= MAX_CHANNUM; chan++) {
162 162 tnode_t *chnode;
163 163 nvlist_t *fmri;
164 164 int err;
165 165
166 166 if (mkrsrc(mod, mcnode, CHAN_NODE_NAME, chan, auth,
167 167 &fmri) != 0) {
168 168 whinge(mod, NULL, "amd_generic_mc_create: mkrsrc "
169 169 "failed\n");
170 170 return (-1);
171 171 }
172 172
173 173 if ((chnode = topo_node_bind(mod, mcnode, CHAN_NODE_NAME,
174 174 chan, fmri)) == NULL) {
175 175 nvlist_free(fmri);
176 176 whinge(mod, NULL, "amd_generic_mc_create: node "
177 177 "bind failed\n");
178 178 return (-1);
179 179 }
180 180
181 181 nvlist_free(fmri);
182 182
183 183 (void) topo_pgroup_create(chnode, &chan_pgroup, &err);
184 184
185 185 (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel",
186 186 TOPO_PROP_IMMUTABLE, chan == 0 ? "A" : "B", &err);
187 187
188 188 if (FM_AWARE_SMBIOS(mod)) {
189 189 if (topo_node_label_set(chnode, NULL, &err) == -1)
190 190 whinge(mod, NULL, "amd_generic_mc_create: "
191 191 "topo_node_label_set\n");
192 192 if (topo_node_fru_set(chnode, NULL, 0, &err) != 0)
193 193 whinge(mod, NULL, "amd_generic_mc_create: "
194 194 "topo_node_fru_set failed\n");
195 195 }
196 196
197 197 if (topo_node_range_create(mod, chnode, CS_NODE_NAME,
198 198 0, MAX_CSNUM) < 0) {
199 199 whinge(mod, NULL, "amd_generic_mc_create: "
200 200 "range create for cs failed\n");
201 201 return (-1);
202 202 }
203 203
204 204 for (cs = 0; cs <= MAX_CSNUM; cs++) {
205 205 tnode_t *csnode;
206 206
207 207 if (mkrsrc(mod, chnode, CS_NODE_NAME, cs, auth,
208 208 &fmri) != 0) {
209 209 whinge(mod, NULL, "amd_generic_mc_create: "
210 210 "mkrsrc for cs failed\n");
211 211 return (-1);
212 212 }
213 213
214 214 if ((csnode = topo_node_bind(mod, chnode, CS_NODE_NAME,
215 215 cs, fmri)) == NULL) {
216 216 nvlist_free(fmri);
217 217 whinge(mod, NULL, "amd_generic_mc_create: "
218 218 "bind for cs failed\n");
219 219 return (-1);
220 220 }
221 221
222 222 /*
223 223 * Dynamic ASRU for page faults within a chip-select.
224 224 * The topology does not represent pages (there are
225 225 * too many) so when a page is faulted we generate
226 226 * an ASRU to represent the individual page.
227 227 * If SMBIOS meets FMA needs, derive labels & serials
228 228 * for DIMMS and apply to chip-select nodes.
229 229 * If deriving from SMBIOS, skip IPMI
230 230 */
231 231 if (FM_AWARE_SMBIOS(mod)) {
232 232 if (topo_method_register(mod, csnode,
233 233 x86pi_gen_cs_methods) < 0)
234 234 whinge(mod, NULL,
235 235 "amd_generic_mc_create: "
236 236 "method registration failed\n");
237 237 } else {
238 238 if (topo_method_register(mod, csnode,
239 239 gen_cs_methods) < 0)
240 240 whinge(mod, NULL,
241 241 "amd_generic_mc_create: method"
242 242 "registration failed\n");
243 243 }
244 244
245 245 (void) topo_node_asru_set(csnode, fmri,
246 246 TOPO_ASRU_COMPUTE, &err);
247 247 nvlist_free(fmri);
248 248
249 249 /*
250 250 * If SMBIOS meets FMA needs, set DIMM as the FRU for
251 251 * the chip-select node. Use the channel & chip-select
252 252 * numbers to get the DIMM instance.
253 253 * Send via inst : dram channel number
254 254 * Receive via inst : dimm instance
255 255 */
256 256 if (FM_AWARE_SMBIOS(mod)) {
257 257 int inst;
258 258 id_t dimm_smbid;
259 259 const char *serial;
260 260 const char *part;
261 261 const char *rev;
262 262 char *label;
263 263
264 264 (void) topo_pgroup_create(csnode,
265 265 &cs_pgroup, &err);
266 266 inst = chan;
267 267 dimm_smbid = memnode_to_smbiosid(mod, smbid,
268 268 CS_NODE_NAME, cs, &inst);
269 269 serial = chip_serial_smbios_get(mod,
270 270 dimm_smbid);
271 271 part = chip_part_smbios_get(mod,
272 272 dimm_smbid);
273 273 rev = chip_rev_smbios_get(mod, dimm_smbid);
274 274 label = (char *)chip_label_smbios_get(mod,
275 275 chnode, dimm_smbid, NULL);
276 276
277 277 (void) topo_prop_set_string(csnode, PGNAME(CS),
278 278 FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
279 279 serial, &err);
280 280 (void) topo_prop_set_string(csnode, PGNAME(CS),
281 281 FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
282 282 part, &err);
283 283 (void) topo_prop_set_string(csnode, PGNAME(CS),
284 284 FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
285 285 rev, &err);
286 286
287 287 /*
288 288 * We apply DIMM labels to chip-select nodes,
289 289 * FRU for chip-selects should be DIMMs, and
290 290 * we do not derive dimm nodes for Family 0x10
291 291 * so FRU fmri is NULL, but FRU Labels are set,
292 292 * the FRU labels point to the DIMM.
293 293 */
294 294 (void) topo_node_label_set(csnode, label, &err);
295 295 topo_mod_strfree(mod, label);
296 296 }
297 297 }
298 298 }
299 299
300 300 return (0);
301 301 }
302 302
303 303 static nvlist_t *
304 304 amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id)
305 305 {
306 306 mc_snapshot_info_t mcs;
307 307 void *buf = NULL;
308 308 uint8_t ver;
309 309
310 310 nvlist_t *nvl = NULL;
311 311 char path[64];
312 312 int fd, err;
313 313
314 314 (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id);
315 315 fd = open(path, O_RDONLY);
316 316
317 317 if (fd == -1) {
318 318 /*
319 319 * Some v20z and v40z systems may have had the 3rd-party
320 320 * NWSnps packagae installed which installs a /dev/mc
321 321 * link. So try again via /devices.
322 322 */
323 323 (void) snprintf(path, sizeof (path),
324 324 "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd",
325 325 MC_AMD_DEV_OFFSET + id);
326 326 fd = open(path, O_RDONLY);
327 327 }
328 328
329 329 if (fd == -1)
330 330 return (NULL); /* do not whinge */
331 331
332 332 if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 ||
333 333 (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL ||
334 334 ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) {
335 335
336 336 whinge(mod, NULL, "mc failed to snapshot %s: %s\n",
337 337 path, strerror(errno));
338 338
339 339 free(buf);
340 340 (void) close(fd);
341 341 return (NULL);
342 342 }
343 343
344 344 (void) close(fd);
345 345 err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0);
346 346 topo_mod_free(mod, buf, mcs.mcs_size);
347 347
348 348 if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) {
349 349 whinge(mod, NULL, "mc nvlist is not versioned\n");
350 350 nvlist_free(nvl);
351 351 return (NULL);
352 352 } else if (ver != MC_NVLIST_VERS1) {
353 353 whinge(mod, NULL, "mc nvlist version mismatch\n");
354 354 nvlist_free(nvl);
355 355 return (NULL);
356 356 }
357 357
358 358 return (err ? NULL : nvl);
359 359 }
360 360
361 361 int
362 362 amd_rank_create(topo_mod_t *mod, tnode_t *pnode, nvlist_t *dimmnvl,
363 363 nvlist_t *auth)
364 364 {
365 365 uint64_t *csnumarr;
366 366 char **csnamearr;
367 367 uint_t ncs, ncsname;
368 368 tnode_t *ranknode;
369 369 nvlist_t *fmri, *pfmri = NULL;
370 370 uint64_t dsz, rsz;
371 371 int nerr = 0;
372 372 int err;
373 373 int i;
374 374
375 375 if (nvlist_lookup_uint64_array(dimmnvl, "csnums", &csnumarr,
376 376 &ncs) != 0 || nvlist_lookup_string_array(dimmnvl, "csnames",
377 377 &csnamearr, &ncsname) != 0 || ncs != ncsname) {
378 378 whinge(mod, &nerr, "amd_rank_create: "
379 379 "csnums/csnames extraction failed\n");
380 380 return (nerr);
381 381 }
382 382
383 383 if (topo_node_resource(pnode, &pfmri, &err) < 0) {
384 384 whinge(mod, &nerr, "amd_rank_create: parent fmri lookup "
385 385 "failed\n");
386 386 return (nerr);
387 387 }
388 388
389 389 if (topo_node_range_create(mod, pnode, RANK_NODE_NAME, 0, ncs) < 0) {
390 390 whinge(mod, &nerr, "amd_rank_create: range create failed\n");
391 391 nvlist_free(pfmri);
392 392 return (nerr);
393 393 }
394 394
395 395 if (topo_prop_get_uint64(pnode, PGNAME(DIMM), "size", &dsz,
396 396 &err) == 0) {
397 397 rsz = dsz / ncs;
398 398 } else {
399 399 whinge(mod, &nerr, "amd_rank_create: parent dimm has no "
400 400 "size\n");
401 401 return (nerr);
402 402 }
403 403
404 404 for (i = 0; i < ncs; i++) {
405 405 if (mkrsrc(mod, pnode, RANK_NODE_NAME, i, auth, &fmri) < 0) {
406 406 whinge(mod, &nerr, "amd_rank_create: mkrsrc failed\n");
407 407 continue;
408 408 }
409 409
410 410 if ((ranknode = topo_node_bind(mod, pnode, RANK_NODE_NAME, i,
411 411 fmri)) == NULL) {
412 412 nvlist_free(fmri);
413 413 whinge(mod, &nerr, "amd_rank_create: node bind "
414 414 "failed\n");
415 415 continue;
416 416 }
417 417
418 418 nvlist_free(fmri);
419 419 if (FM_AWARE_SMBIOS(mod))
420 420 (void) topo_node_fru_set(ranknode, NULL, 0, &err);
421 421 else
422 422 (void) topo_node_fru_set(ranknode, pfmri, 0, &err);
423 423
424 424 /*
425 425 * If a rank is faulted the asru is the associated
426 426 * chip-select, but if a page within a rank is faulted
427 427 * the asru is just that page. Hence the dual preconstructed
428 428 * and computed ASRU.
429 429 */
430 430 if (topo_method_register(mod, ranknode, rank_methods) < 0)
431 431 whinge(mod, &nerr, "amd_rank_create: "
432 432 "topo_method_register failed");
433 433
434 434 if (! is_xpv() && topo_method_register(mod, ranknode,
435 435 ntv_page_retire_methods) < 0)
436 436 whinge(mod, &nerr, "amd_rank_create: "
437 437 "topo_method_register failed");
438 438
439 439 (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]],
440 440 TOPO_ASRU_COMPUTE, &err);
441 441
442 442 (void) topo_pgroup_create(ranknode, &rank_pgroup, &err);
443 443
444 444 (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size",
445 445 TOPO_PROP_IMMUTABLE, rsz, &err);
446 446
447 447 (void) topo_prop_set_string(ranknode, PGNAME(RANK), "csname",
448 448 TOPO_PROP_IMMUTABLE, csnamearr[i], &err);
449 449
450 450 (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "csnum",
451 451 TOPO_PROP_IMMUTABLE, csnumarr[i], &err);
452 452 }
453 453
454 454 nvlist_free(pfmri);
455 455
456 456 return (nerr);
457 457 }
458 458
459 459 static int
460 460 amd_dimm_create(topo_mod_t *mod, uint16_t chip_smbid, tnode_t *pnode,
461 461 const char *name, nvlist_t *mc, nvlist_t *auth)
462 462 {
463 463 int i, err, nerr = 0;
464 464 int perr = 0;
465 465 nvpair_t *nvp;
466 466 tnode_t *dimmnode;
467 467 nvlist_t *fmri, **dimmarr = NULL;
468 468 uint64_t num;
469 469 uint_t ndimm;
470 470 id_t smbid;
471 471 const char *serial;
472 472 const char *part;
473 473 const char *rev;
474 474
475 475 if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) {
476 476 whinge(mod, NULL, "amd_dimm_create: dimmlist lookup failed\n");
477 477 return (-1);
478 478 }
479 479
480 480 if (ndimm == 0)
481 481 return (0); /* no dimms present on this node */
482 482
483 483 if (topo_node_range_create(mod, pnode, name, 0, MAX_DIMMNUM) < 0) {
484 484 whinge(mod, NULL, "amd_dimm_create: range create failed\n");
485 485 return (-1);
486 486 }
487 487
488 488 for (i = 0; i < ndimm; i++) {
489 489 if (nvlist_lookup_uint64(dimmarr[i], "num", &num) != 0) {
490 490 whinge(mod, &nerr, "amd_dimm_create: dimm num property "
491 491 "missing\n");
492 492 continue;
493 493 }
494 494
495 495 if (mkrsrc(mod, pnode, name, num, auth, &fmri) < 0) {
496 496 whinge(mod, &nerr, "amd_dimm_create: mkrsrc failed\n");
497 497 continue;
498 498 }
499 499 if (FM_AWARE_SMBIOS(mod)) {
500 500 smbid = memnode_to_smbiosid(mod, chip_smbid,
501 501 DIMM_NODE_NAME, i, NULL);
502 502 serial = chip_serial_smbios_get(mod, smbid);
503 503 part = chip_part_smbios_get(mod, smbid);
504 504 rev = chip_rev_smbios_get(mod, smbid);
505 505 perr += nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
506 506 serial);
507 507 perr += nvlist_add_string(fmri, FM_FMRI_HC_PART,
508 508 part);
509 509 perr += nvlist_add_string(fmri, FM_FMRI_HC_REVISION,
510 510 rev);
511 511
512 512 if (perr != 0)
513 513 whinge(mod, NULL, "amd_dimm_create:"
514 514 "nvlist_add_string failed\n");
515 515 }
516 516
517 517 if ((dimmnode = topo_node_bind(mod, pnode, name, num, fmri))
518 518 == NULL) {
519 519 nvlist_free(fmri);
520 520 whinge(mod, &nerr, "amd_dimm_create: node bind "
521 521 "failed\n");
522 522 continue;
523 523 }
524 524
525 525 if (!FM_AWARE_SMBIOS(mod))
526 526 if (topo_method_register(mod,
527 527 dimmnode, dimm_methods) < 0)
528 528 whinge(mod, &nerr, "amd_dimm_create: "
529 529 "topo_method_register failed");
530 530
531 531 (void) topo_pgroup_create(dimmnode, &dimm_pgroup, &err);
532 532
533 533 if (FM_AWARE_SMBIOS(mod)) {
534 534 char *label;
535 535
536 536 nvlist_free(fmri);
537 537 (void) topo_node_resource(dimmnode,
538 538 &fmri, &err);
539 539
540 540 label = (char *)chip_label_smbios_get(mod,
541 541 pnode, smbid, NULL);
542 542 if (topo_node_label_set(dimmnode, label,
543 543 &perr) == -1)
544 544 topo_mod_dprintf(mod, "Failed"
545 545 "to set label\n");
546 546 topo_mod_strfree(mod, label);
547 547
548 548 (void) topo_prop_set_string(dimmnode, PGNAME(DIMM),
549 549 FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
550 550 serial, &err);
551 551 (void) topo_prop_set_string(dimmnode, PGNAME(DIMM),
552 552 FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
553 553 part, &err);
554 554 (void) topo_prop_set_string(dimmnode, PGNAME(DIMM),
555 555 FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
556 556 rev, &err);
557 557 }
558 558
559 559 (void) topo_node_asru_set(dimmnode, fmri, 0, &err);
560 560 (void) topo_node_fru_set(dimmnode, fmri, 0, &err);
561 561 nvlist_free(fmri);
562 562
563 563 for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL;
564 564 nvp = nvlist_next_nvpair(dimmarr[i], nvp)) {
565 565 if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY &&
566 566 strcmp(nvpair_name(nvp), "csnums") == 0 ||
567 567 nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY &&
568 568 strcmp(nvpair_name(nvp), "csnames") == 0)
569 569 continue; /* used in amd_rank_create() */
570 570
571 571 nerr += nvprop_add(mod, nvp, PGNAME(DIMM), dimmnode);
572 572 }
573 573
574 574 nerr += amd_rank_create(mod, dimmnode, dimmarr[i], auth);
575 575 }
576 576
577 577 return (nerr == 0 ? 0 : -1);
578 578 }
579 579
580 580 static int
581 581 amd_cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc,
582 582 nvlist_t *auth)
583 583 {
584 584 int i, err, nerr = 0;
585 585 nvpair_t *nvp;
586 586 tnode_t *csnode;
587 587 nvlist_t *fmri, **csarr = NULL;
588 588 uint64_t csnum;
589 589 uint_t ncs;
590 590
591 591 if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0)
592 592 return (-1);
593 593
594 594 if (ncs == 0)
595 595 return (0); /* no chip-selects configured on this node */
596 596
597 597 if (topo_node_range_create(mod, pnode, name, 0, MAX_CSNUM) < 0)
598 598 return (-1);
599 599
600 600 for (i = 0; i < ncs; i++) {
601 601 if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) {
602 602 whinge(mod, &nerr, "amd_cs_create: cs num property "
603 603 "missing\n");
604 604 continue;
605 605 }
606 606
607 607 if (mkrsrc(mod, pnode, name, csnum, auth, &fmri) != 0) {
608 608 whinge(mod, &nerr, "amd_cs_create: mkrsrc failed\n");
609 609 continue;
610 610 }
611 611
612 612 if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri))
613 613 == NULL) {
614 614 nvlist_free(fmri);
615 615 whinge(mod, &nerr, "amd_cs_create: node bind failed\n");
616 616 continue;
617 617 }
618 618
619 619 cs_fmri[csnum] = fmri; /* nvlist will be freed in mc_create */
620 620
621 621 (void) topo_node_asru_set(csnode, fmri, 0, &err);
622 622
623 623 (void) topo_node_fru_set(csnode, fmri, 0, &err);
624 624
625 625 (void) topo_pgroup_create(csnode, &cs_pgroup, &err);
626 626
627 627 for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL;
628 628 nvp = nvlist_next_nvpair(csarr[i], nvp)) {
629 629 nerr += nvprop_add(mod, nvp, PGNAME(CS), csnode);
630 630 }
631 631 }
632 632
633 633 return (nerr == 0 ? 0 : -1);
634 634 }
635 635
636 636 static int
637 637 amd_dramchan_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
638 638 nvlist_t *auth)
639 639 {
640 640 tnode_t *chnode;
641 641 nvlist_t *fmri;
642 642 char *socket;
643 643 int i, nchan;
644 644 nvlist_t *pfmri = NULL;
645 645 int err, nerr = 0;
646 646
647 647 /*
648 648 * We will enumerate the number of channels present even if only
649 649 * channel A is in use (i.e., running in 64-bit mode). Only
650 650 * the socket 754 package has a single channel.
651 651 */
652 652 if (topo_prop_get_string(pnode, PGNAME(MCT), "socket",
653 653 &socket, &err) == 0 && strcmp(socket, "Socket 754") == 0)
654 654 nchan = 1;
655 655 else
656 656 nchan = 2;
657 657
658 658 topo_mod_strfree(mod, socket);
659 659
660 660 if (topo_node_range_create(mod, pnode, name, 0, nchan - 1) < 0)
661 661 return (-1);
662 662
663 663 (void) topo_node_fru(pnode, &pfmri, NULL, &err);
664 664
665 665 for (i = 0; i < nchan; i++) {
666 666 if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) {
667 667 whinge(mod, &nerr, "amd_dramchan_create: mkrsrc "
668 668 "failed\n");
669 669 continue;
670 670 }
671 671
672 672 if ((chnode = topo_node_bind(mod, pnode, name, i, fmri))
673 673 == NULL) {
674 674 nvlist_free(fmri);
675 675 whinge(mod, &nerr, "amd_dramchan_create: node bind "
676 676 "failed\n");
677 677 continue;
678 678 }
679 679
680 680 (void) topo_node_asru_set(chnode, fmri, 0, &err);
↓ open down ↓ |
680 lines elided |
↑ open up ↑ |
681 681 if (pfmri)
682 682 (void) topo_node_fru_set(chnode, pfmri, 0, &err);
683 683
684 684 nvlist_free(fmri);
685 685
686 686 (void) topo_pgroup_create(chnode, &chan_pgroup, &err);
687 687
688 688 (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel",
689 689 TOPO_PROP_IMMUTABLE, i == 0 ? "A" : "B", &err);
690 690 }
691 - if (pfmri)
692 - nvlist_free(pfmri);
691 + nvlist_free(pfmri);
693 692
694 693 return (nerr == 0 ? 0 : -1);
695 694 }
696 695
697 696 static int
698 697 amd_htconfig(topo_mod_t *mod, tnode_t *cnode, nvlist_t *htnvl)
699 698 {
700 699 nvpair_t *nvp;
701 700 int nerr = 0;
702 701
703 702 if (strcmp(topo_node_name(cnode), CHIP_NODE_NAME) != 0) {
704 703 whinge(mod, &nerr, "amd_htconfig: must pass a chip node!");
705 704 return (-1);
706 705 }
707 706
708 707 for (nvp = nvlist_next_nvpair(htnvl, NULL); nvp != NULL;
709 708 nvp = nvlist_next_nvpair(htnvl, nvp)) {
710 709 if (nvprop_add(mod, nvp, PGNAME(CHIP), cnode) != 0)
711 710 nerr++;
712 711 }
713 712
714 713 return (nerr == 0 ? 0 : -1);
715 714 }
716 715
717 716 void
718 717 amd_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *pnode,
719 718 const char *name, nvlist_t *auth, int32_t procnodeid,
720 719 int32_t procnodes_per_pkg, int family,
721 720 int model, int *nerrp)
722 721 {
723 722 tnode_t *mcnode;
724 723 nvlist_t *rfmri, *fmri;
725 724 nvpair_t *nvp;
726 725 nvlist_t *mc = NULL;
727 726 int i, err;
728 727 int mcnum = procnodeid % procnodes_per_pkg;
729 728 char *serial = NULL;
730 729 char *part = NULL;
731 730 char *rev = NULL;
732 731
733 732 /*
734 733 * Return with no error for anything before AMD family 0xf - we
735 734 * won't generate even a generic memory topology for earlier
736 735 * families.
737 736 */
738 737 if (family < 0xf)
739 738 return;
740 739
741 740 if (topo_node_lookup(pnode, name, mcnum) != NULL)
742 741 return;
743 742
744 743 if (FM_AWARE_SMBIOS(mod)) {
745 744 (void) topo_node_resource(pnode, &rfmri, &err);
746 745 (void) nvlist_lookup_string(rfmri, "serial", &serial);
747 746 (void) nvlist_lookup_string(rfmri, "part", &part);
748 747 (void) nvlist_lookup_string(rfmri, "revision", &rev);
749 748 }
750 749
751 750 if (mkrsrc(mod, pnode, name, mcnum, auth, &fmri) != 0) {
752 751 if (FM_AWARE_SMBIOS(mod))
753 752 nvlist_free(rfmri);
754 753 whinge(mod, nerrp, "mc_create: mkrsrc failed\n");
755 754 return;
756 755 }
757 756
758 757 if (FM_AWARE_SMBIOS(mod)) {
759 758 (void) nvlist_add_string(fmri, "serial", serial);
760 759 (void) nvlist_add_string(fmri, "part", part);
761 760 (void) nvlist_add_string(fmri, "revision", rev);
762 761 nvlist_free(rfmri);
763 762 }
764 763
765 764 if ((mcnode = topo_node_bind(mod, pnode, name, mcnum,
766 765 fmri)) == NULL) {
767 766 nvlist_free(fmri);
768 767 whinge(mod, nerrp, "mc_create: mc bind failed\n");
769 768 return;
770 769 }
771 770 if (topo_node_fru_set(mcnode, NULL, 0, &err) < 0)
772 771 whinge(mod, nerrp, "mc_create: topo_node_fru_set failed\n");
773 772
774 773 if (FM_AWARE_SMBIOS(mod)) {
775 774 if (topo_node_label_set(mcnode, NULL, &err) == -1)
776 775 topo_mod_dprintf(mod, "Failed to set label\n");
777 776 }
778 777
779 778 nvlist_free(fmri);
780 779
781 780 if (topo_pgroup_create(mcnode, &mc_pgroup, &err) < 0)
782 781 whinge(mod, nerrp, "mc_create: topo_pgroup_create failed\n");
783 782
784 783 if (topo_prop_set_int32(mcnode, PGNAME(MCT), MCT_PROCNODE_ID,
785 784 TOPO_PROP_IMMUTABLE, procnodeid, nerrp) != 0)
786 785 whinge(mod, nerrp, "mc_create: topo_prop_set_int32 failed to"
787 786 "add node id\n");
788 787
789 788 if ((mc = amd_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL) {
790 789 /*
791 790 * If a memory-controller driver exists for this chip model
792 791 * it has not attached or has otherwise malfunctioned;
793 792 * alternatively no memory-controller driver exists for this
794 793 * (presumably newly-released) cpu model. We fallback to
795 794 * creating a generic maximal topology.
796 795 */
797 796 if (amd_generic_mc_create(mod, smbid, pnode, mcnode,
798 797 family, model, auth) != 0)
799 798 whinge(mod, nerrp,
800 799 "mc_create: amd_generic_mc_create failed\n");
801 800 return;
802 801 }
803 802
804 803 /*
805 804 * Add memory controller properties
806 805 */
807 806 for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL;
808 807 nvp = nvlist_next_nvpair(mc, nvp)) {
809 808 char *name = nvpair_name(nvp);
810 809 data_type_t type = nvpair_type(nvp);
811 810
812 811 if (type == DATA_TYPE_NVLIST_ARRAY &&
813 812 (strcmp(name, "cslist") == 0 ||
814 813 strcmp(name, "dimmlist") == 0)) {
815 814 continue;
816 815 } else if (type == DATA_TYPE_UINT8 &&
817 816 strcmp(name, MC_NVLIST_VERSTR) == 0) {
818 817 continue;
819 818 } else if (type == DATA_TYPE_NVLIST &&
820 819 strcmp(name, "htconfig") == 0) {
821 820 nvlist_t *htnvl;
822 821
823 822 (void) nvpair_value_nvlist(nvp, &htnvl);
824 823 if (amd_htconfig(mod, pnode, htnvl) != 0)
825 824 whinge(mod, nerrp,
826 825 "mc_create: amd_htconfig failed\n");
827 826 } else {
828 827 if (nvprop_add(mod, nvp, PGNAME(MCT), mcnode) != 0)
829 828 whinge(mod, nerrp,
830 829 "mc_create: nvprop_add failed\n");
831 830 }
832 831 }
833 832
834 833 if (amd_dramchan_create(mod, mcnode, CHAN_NODE_NAME, auth) != 0 ||
835 834 amd_cs_create(mod, mcnode, CS_NODE_NAME, mc, auth) != 0 ||
836 835 amd_dimm_create(mod, smbid, mcnode, DIMM_NODE_NAME, mc, auth) != 0)
837 836 whinge(mod, nerrp, "mc_create: create children failed\n");
838 837
839 838 /*
840 839 * Free the fmris for the chip-selects allocated in amd_cs_create
841 840 */
842 841 for (i = 0; i < MC_CHIP_NCS; i++) {
843 842 if (cs_fmri[i] != NULL) {
844 843 nvlist_free(cs_fmri[i]);
845 844 cs_fmri[i] = NULL;
846 845 }
847 846 }
848 847
849 848 nvlist_free(mc);
850 849 }
↓ open down ↓ |
148 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX