Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0
2 : : /* Copyright 2013-2019 IBM Corp. */
3 : :
4 : : #include <skiboot.h>
5 : : #include <vpd.h>
6 : : #include <string.h>
7 : : #include "spira.h"
8 : : #include "hdata.h"
9 : : #include <device.h>
10 : : #include "hdata.h"
11 : : #include <inttypes.h>
12 : : #include <mem_region-malloc.h>
13 : :
14 : : struct card_info {
15 : : const char *ccin; /* Customer card identification number */
16 : : const char *description;
17 : : };
18 : :
19 : : static const struct card_info card_table[] = {
20 : : {"2B06", "System planar 2S4U"},
21 : : {"2B07", "System planar 1S4U"},
22 : : {"2B2E", "System planar 2S2U"},
23 : : {"2B2F", "System planar 1S2U"},
24 : : {"2CD4", "System planar 2S4U"},
25 : : {"2CD5", "System planar 1S4U"},
26 : : {"2CD6", "System planar 2S2U"},
27 : : {"2CD7", "System planar 1S2U"},
28 : : {"2CD7", "System planar 1S2U"},
29 : : {"2B09", "Base JBOD, RAID and Backplane HD"},
30 : : {"57D7", "Split JBOD, RAID Card"},
31 : : {"2B0B", "Native I/O Card"},
32 : :
33 : : /* Anchor cards */
34 : : {"52FE", "System Anchor Card - IBM Power 824"},
35 : : {"52F2", "System Anchor Card - IBM Power 814"},
36 : : {"52F5", "System Anchor Card - IBM Power 822"},
37 : : {"561A", "System Anchor Card - IBM Power 824L"},
38 : : {"524D", "System Anchor Card - IBM Power 822L"},
39 : : {"560F", "System Anchor Card - IBM Power 812L"},
40 : : {"561C", "System Anchor Card - DS8870"},
41 : :
42 : : /* Memory DIMMs */
43 : : {"31E0", "16GB CDIMM"},
44 : : {"31E8", "16GB CDIMM"},
45 : : {"31E1", "32GB CDIMM"},
46 : : {"31E9", "32GB CDIMM"},
47 : : {"31E2", "64GB CDIMM"},
48 : : {"31EA", "64GB CDIMM"},
49 : :
50 : : /* Power supplies */
51 : : {"2B1D", "Power Supply 900W AC"},
52 : : {"2B1E", "Power Supply 1400W AC"},
53 : : {"2B75", "Power Supply 1400W HVDC"},
54 : :
55 : : /* Fans */
56 : : {"2B1F", "Fan 4U (A1, A2, A3, A4)"},
57 : : {"2B29", "Fan 2U (A1, A2, A3, A4, A5, A6)"},
58 : :
59 : : /* Other cards */
60 : : };
61 : :
62 : : struct vpd_key_map {
63 : : const char *keyword; /* 2 char keyword */
64 : : const char *description;
65 : : };
66 : :
67 : : static const struct vpd_key_map vpd_key_table[] = {
68 : : {"AA", "ac-power-supply"},
69 : : {"AM", "air-mover"},
70 : : {"AV", "anchor-card"},
71 : :
72 : : {"BA", "bus-adapter-card"},
73 : : {"BC", "battery-charger"},
74 : : {"BD", "bus-daughter-card"},
75 : : {"BE", "bus-expansion-card"},
76 : : {"BP", "backplane"},
77 : : {"BR", "backplane-riser"},
78 : : {"BX", "backplane-extender"},
79 : :
80 : : {"CA", "calgary-bridge"},
81 : : {"CB", "infiniband-connector"},
82 : : {"CC", "clock-card"},
83 : : {"CD", "card-connector"},
84 : : {"CE", "ethernet-connector"},
85 : : {"CL", "calgary-phb"},
86 : : {"CI", "capacity-card"},
87 : : {"CO", "sma-connector"},
88 : : {"CP", "processor-capacity-card"},
89 : : {"CR", "rio-connector"},
90 : : {"CS", "serial-connector"},
91 : : {"CU", "usb-connector"},
92 : :
93 : : {"DB", "dasd-backplane"},
94 : : {"DC", "drawer-card"},
95 : : {"DE", "drawer-extension"},
96 : : {"DI", "drawer-interposer"},
97 : : {"DL", "p7ih-dlink-connector"},
98 : : {"DT", "legacy-pci-card"},
99 : : {"DV", "media-drawer-led"},
100 : :
101 : : {"EI", "enclosure-led"},
102 : : {"EF", "enclosure-fault-led"},
103 : : {"ES", "embedded-sas"},
104 : : {"ET", "ethernet-riser"},
105 : : {"EV", "enclosure"},
106 : :
107 : : {"FM", "frame"},
108 : : {"FN", "fru-stocking-part-number"},
109 : :
110 : : {"HB", "host-rio-pci-card"},
111 : : {"HD", "high-speed-card"},
112 : : {"HM", "hmc-connector"},
113 : :
114 : : {"IB", "io-backplane"},
115 : : {"IC", "io-card"},
116 : : {"ID", "ide-connector"},
117 : : {"II", "io-drawer-led"},
118 : : {"IP", "interplane-card"},
119 : : {"IS", "smp-vbus-cable"},
120 : : {"IT", "enclosure-cable"},
121 : : {"IV", "io-enclosure"},
122 : :
123 : : {"KV", "keyboard-led"},
124 : :
125 : : {"L2", "l2-cache-module"},
126 : : {"L3", "l3-cache-module"},
127 : : {"LC", "squadrons-light-connector"},
128 : : {"LR", "p7ih-connector"},
129 : : {"LO", "system-locate-led"},
130 : : {"LT", "squadrons-light-strip"},
131 : :
132 : : {"MB", "media-backplane"},
133 : : {"ME", "map-extension"},
134 : : {"MM", "mip-meter"},
135 : : {"MS", "ms-dimm"},
136 : :
137 : : {"NB", "nvram-battery"},
138 : : {"NC", "sp-node-controller"},
139 : : {"ND", "numa-dimm"},
140 : :
141 : : {"OD", "cuod-card"},
142 : : {"OP", "op-panel"},
143 : : {"OS", "oscillator"},
144 : :
145 : : {"P2", "ioc"},
146 : : {"P5", "ioc-bridge"},
147 : : {"PB", "io-drawer-backplane"},
148 : : {"PC", "power-capacitor"},
149 : : {"PD", "processor-card"},
150 : : {"PF", "processor"},
151 : : {"PI", "ioc-phb"},
152 : : {"PO", "spcn"},
153 : : {"PN", "spcn-connector"},
154 : : {"PR", "pci-riser-card"},
155 : : {"PS", "power-supply"},
156 : : {"PT", "pass-through-card"},
157 : : {"PX", "psc-sync-card"},
158 : : {"PW", "power-connector"},
159 : :
160 : : {"RG", "regulator"},
161 : : {"RI", "riser"},
162 : : {"RK", "rack-indicator"},
163 : : {"RW", "riscwatch-connector"},
164 : :
165 : : {"SA", "sys-attn-led"},
166 : : {"SB", "backup-sysvpd"},
167 : : {"SC", "scsi-connector"},
168 : : {"SD", "sas-connector"},
169 : : {"SI", "scsi-ide-converter"},
170 : : {"SL", "phb-slot"},
171 : : {"SN", "smp-cable-connector"},
172 : : {"SP", "service-processor"},
173 : : {"SR", "service-card"},
174 : : {"SS", "soft-switch"},
175 : : {"SV", "system-vpd"},
176 : : {"SY", "legacy-sysvpd"},
177 : :
178 : : {"TD", "tod-clock"},
179 : : {"TI", "torrent-pcie-phb"},
180 : : {"TL", "torrent-riser"},
181 : : {"TM", "thermal-sensor"},
182 : : {"TP", "tpmd-adapter"},
183 : : {"TR", "torrent-bridge"},
184 : :
185 : : {"VV", "root-node-vpd"},
186 : :
187 : : {"WD", "water_device"},
188 : : };
189 : :
190 : 68 : static const char *vpd_map_name(const char *vpd_name)
191 : : {
192 : : int i;
193 : :
194 : 2324 : for (i = 0; i < ARRAY_SIZE(vpd_key_table); i++)
195 : 2324 : if (!strcmp(vpd_key_table[i].keyword, vpd_name))
196 : 68 : return vpd_key_table[i].description;
197 : :
198 : 0 : prlog(PR_WARNING, "VPD: Could not map FRU ID %s to a known name\n",
199 : : vpd_name);
200 : :
201 : 0 : return "Unknown";
202 : : }
203 : :
204 : 10 : static const struct card_info *card_info_lookup(char *ccin)
205 : : {
206 : : int i;
207 : 177 : for(i = 0; i < ARRAY_SIZE(card_table); i++)
208 : : /* CCIN is always 4 bytes in size */
209 : 174 : if (!strncmp(card_table[i].ccin, ccin, 4))
210 : 7 : return &card_table[i];
211 : 3 : return NULL;
212 : : }
213 : :
214 : : /* Discard trailing spaces and populate device tree */
215 : 90 : static struct dt_property *dt_add_prop_sanitize_val(struct dt_node *node,
216 : : const char *name, const char *val, int vlen)
217 : : {
218 : 90 : char *prop = zalloc(vlen + 1);
219 : : int i;
220 : 90 : struct dt_property *p = NULL;
221 : :
222 : 90 : if (!prop)
223 : 0 : return p;
224 : :
225 : 90 : memcpy(prop, val, vlen);
226 : 94 : for (i = vlen - 1; i >= 0; i--) {
227 : 94 : if (prop[i] != 0x20) {
228 : 90 : prop[i + 1] = '\0';
229 : 90 : break;
230 : : }
231 : : }
232 : :
233 : 90 : if (i >= 0 && !dt_find_property(node, name))
234 : 90 : p = dt_add_property_string(node, name, prop);
235 : :
236 : 90 : free(prop);
237 : 90 : return p;
238 : : }
239 : :
240 : : /*
241 : : * OpenPower system does not provide processor vendor name under FRU VPD.
242 : : * Parse processor module VPD to get vendor detail
243 : : */
244 : 2 : void dt_add_proc_vendor(struct dt_node *proc_node,
245 : : const void *mvpd, unsigned int mvpd_sz)
246 : : {
247 : : const void *kw;
248 : : uint8_t sz;
249 : :
250 : 2 : kw = vpd_find(mvpd, mvpd_sz, "VINI", "VN", &sz);
251 : 2 : if (kw)
252 : 0 : dt_add_prop_sanitize_val(proc_node, "vendor", kw, sz);
253 : 2 : }
254 : :
255 : : /*
256 : : * For OpenPOWER, we only decipher OPFR records. While OP HDAT have VINI
257 : : * records too, populating the fields in there is optional. Also, there
258 : : * is an overlap in the fields contained therein.
259 : : */
260 : 0 : static void vpd_opfr_parse(struct dt_node *node,
261 : : const void *fruvpd, unsigned int fruvpd_sz)
262 : : {
263 : : const void *kw;
264 : : uint8_t sz;
265 : :
266 : : /* Vendor Name */
267 : 0 : kw = vpd_find(fruvpd, fruvpd_sz, "OPFR", "VN", &sz);
268 : 0 : if (kw)
269 : 0 : dt_add_prop_sanitize_val(node, "vendor", kw, sz);
270 : :
271 : : /* FRU Description */
272 : 0 : kw = vpd_find(fruvpd, fruvpd_sz, "OPFR", "DR", &sz);
273 : 0 : if (kw)
274 : 0 : dt_add_prop_sanitize_val(node, "description", kw, sz);
275 : :
276 : : /* Part number */
277 : 0 : kw = vpd_find(fruvpd, fruvpd_sz, "OPFR", "VP", &sz);
278 : 0 : if (kw)
279 : 0 : dt_add_prop_sanitize_val(node, "part-number", kw, sz);
280 : :
281 : : /* Serial number */
282 : 0 : kw = vpd_find(fruvpd, fruvpd_sz, "OPFR", "VS", &sz);
283 : 0 : if (kw)
284 : 0 : dt_add_prop_sanitize_val(node, "serial-number", kw, sz);
285 : :
286 : : /* Build date in BCD */
287 : 0 : kw = vpd_find(fruvpd, fruvpd_sz, "OPFR", "MB", &sz);
288 : 0 : if (kw)
289 : 0 : dt_add_prop_sanitize_val(node, "build-date", kw, sz);
290 : :
291 : 0 : return;
292 : : }
293 : :
294 : : /*
295 : : * For CPUs, parse the VRML data.
296 : : */
297 : 2 : static void vpd_vrml_parse(struct dt_node *node,
298 : : const void *fruvpd, unsigned int fruvpd_sz)
299 : : {
300 : : const void *kw;
301 : : uint8_t sz;
302 : :
303 : : /* Part number */
304 : 2 : kw = vpd_find(fruvpd, fruvpd_sz, "VRML", "PN", &sz);
305 : 2 : if (kw)
306 : 2 : dt_add_prop_sanitize_val(node, "part-number", kw, sz);
307 : :
308 : : /* Serial number */
309 : 2 : kw = vpd_find(fruvpd, fruvpd_sz, "VRML", "SN", &sz);
310 : 2 : if (kw)
311 : 2 : dt_add_prop_sanitize_val(node, "serial-number", kw, sz);
312 : :
313 : 2 : return;
314 : : }
315 : :
316 : 10 : static void vpd_vini_parse(struct dt_node *node,
317 : : const void *fruvpd, unsigned int fruvpd_sz)
318 : : {
319 : : const void *kw;
320 : : const char *desc;
321 : : uint8_t sz;
322 : : const struct card_info *cinfo;
323 : :
324 : : /* FRU Stocking Part Number */
325 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "FN", &sz);
326 : 10 : if (kw)
327 : 10 : dt_add_prop_sanitize_val(node, "fru-number", kw, sz);
328 : :
329 : : /* Serial Number */
330 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "SN", &sz);
331 : 10 : if (kw)
332 : 10 : dt_add_prop_sanitize_val(node, "serial-number", kw, sz);
333 : :
334 : : /* Part Number */
335 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "PN", &sz);
336 : 10 : if (kw)
337 : 10 : dt_add_prop_sanitize_val(node, "part-number", kw, sz);
338 : :
339 : : /* Vendor Name */
340 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "VN", &sz);
341 : 10 : if (kw)
342 : 0 : dt_add_prop_sanitize_val(node, "vendor", kw, sz);
343 : :
344 : : /* CCIN Extension */
345 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "CE", &sz);
346 : 10 : if (kw)
347 : 10 : dt_add_prop_sanitize_val(node, "ccin-extension", kw, sz);
348 : :
349 : : /* HW Version info */
350 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "HW", &sz);
351 : 10 : if (kw)
352 : 10 : dt_add_prop_sanitize_val(node, "hw-version", kw, sz);
353 : :
354 : : /* Card type info */
355 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "CT", &sz);
356 : 10 : if (kw)
357 : 10 : dt_add_prop_sanitize_val(node, "card-type", kw, sz);
358 : :
359 : : /* HW characteristics info */
360 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "B3", &sz);
361 : 10 : if (kw)
362 : 10 : dt_add_prop_sanitize_val(node, "hw-characteristics", kw, sz);
363 : :
364 : : /* Customer Card Identification Number (CCIN) */
365 : 10 : kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "CC", &sz);
366 : 10 : if (kw) {
367 : 10 : dt_add_prop_sanitize_val(node, "ccin", kw, sz);
368 : :
369 : 10 : cinfo = card_info_lookup((char *)kw);
370 : 10 : if (cinfo) {
371 : 7 : dt_add_property_string(node,
372 : 7 : "description", cinfo->description);
373 : : } else {
374 : 3 : desc = vpd_find(fruvpd, fruvpd_sz, "VINI", "DR", &sz);
375 : 3 : if (desc) {
376 : 3 : dt_add_prop_sanitize_val(node,
377 : : "description", desc, sz);
378 : : } else {
379 : 0 : dt_add_property_string(node, "description", "Unknown");
380 : 0 : prlog(PR_WARNING,
381 : : "VPD: CCIN desc not available for: %s\n",
382 : : (char*)kw);
383 : : }
384 : : }
385 : : }
386 : :
387 : 10 : return;
388 : : }
389 : :
390 : 69 : static bool valid_child_entry(const struct slca_entry *entry)
391 : : {
392 : 69 : if ((entry->install_indic == SLCA_INSTALL_INSTALLED) &&
393 : 29 : (entry->vpd_collected == SLCA_VPD_COLLECTED))
394 : 29 : return true;
395 : :
396 : 40 : return false;
397 : : }
398 : :
399 : 12 : void vpd_data_parse(struct dt_node *node, const void *fruvpd, u32 fruvpd_sz)
400 : : {
401 : 12 : if (vpd_find_record(fruvpd, fruvpd_sz, "OPFR", NULL))
402 : 0 : vpd_opfr_parse(node, fruvpd, fruvpd_sz);
403 : 12 : else if (vpd_find_record(fruvpd, fruvpd_sz, "VRML", NULL))
404 : 2 : vpd_vrml_parse(node, fruvpd, fruvpd_sz);
405 : : else
406 : 10 : vpd_vini_parse(node, fruvpd, fruvpd_sz);
407 : 12 : }
408 : :
409 : : /* Create the /vpd node and add its children */
410 : 1 : void dt_init_vpd_node(void)
411 : : {
412 : : const char *name, *p_name;
413 : : int count, index;
414 : : uint64_t addr, p_addr;
415 : : struct dt_node *dt_vpd;
416 : : struct HDIF_common_hdr *slca_hdr;
417 : : struct dt_node *parent, *node;
418 : : const struct slca_entry *entry, *p_entry;
419 : :
420 : 1 : dt_vpd = dt_new(dt_root, "vpd");
421 : 1 : assert(dt_vpd);
422 : 1 : dt_add_property_string(dt_vpd, "compatible", "ibm,opal-v3-vpd");
423 : 1 : dt_add_property_cells(dt_vpd, "#size-cells", 0);
424 : 1 : dt_add_property_cells(dt_vpd, "#address-cells", 1);
425 : :
426 : 1 : slca_hdr = get_hdif(&spiras->ntuples.slca, SLCA_HDIF_SIG);
427 : 1 : if (!slca_hdr) {
428 : 0 : prerror("SLCA Invalid\n");
429 : 0 : return;
430 : : }
431 : :
432 : 1 : count = HDIF_get_iarray_size(slca_hdr, SLCA_IDATA_ARRAY);
433 : 1 : if (count < 0) {
434 : 0 : prerror("SLCA: Can't find SLCA array size!\n");
435 : 0 : return;
436 : : }
437 : :
438 : 70 : for (index = 0; index < count; index++) {
439 : : /* Get SLCA entry */
440 : 69 : entry = slca_get_entry(index);
441 : 69 : if (!entry)
442 : 0 : continue;
443 : :
444 : : /*
445 : : * A child entry is valid if all of the following criteria is met
446 : : * a. SLCA_INSTALL_INSTALLED is set in s_entry->install_indic
447 : : * b. SLCA_VPD_COLLECTED is set in s_entry->vpd_collected
448 : : * c. The SLCA is not a duplicate entry.
449 : : */
450 : 69 : if (!valid_child_entry(entry))
451 : 40 : goto next_entry;
452 : :
453 : 29 : name = vpd_map_name(entry->fru_id);
454 : 29 : addr = be16_to_cpu(entry->rsrc_id);
455 : : /* Check node is already created or not */
456 : 29 : if (dt_find_by_name_addr(dt_vpd, name, addr))
457 : 0 : goto next_entry;
458 : :
459 : : /* Get parent node */
460 : 29 : if (index == SLCA_ROOT_INDEX) {
461 : 1 : parent = dt_vpd;
462 : : } else {
463 : 28 : p_entry = slca_get_entry(be16_to_cpu(entry->parent_index));
464 : 28 : if (!p_entry)
465 : 0 : goto next_entry;
466 : 28 : p_name = vpd_map_name(p_entry->fru_id);
467 : 28 : p_addr = be16_to_cpu(p_entry->rsrc_id);
468 : 28 : parent = dt_find_by_name_addr(dt_vpd, p_name, p_addr);
469 : : }
470 : 29 : if (!parent)
471 : 0 : goto next_entry;
472 : :
473 : 29 : node = dt_new_addr(parent, name, addr);
474 : 29 : if (!node) {
475 : 0 : prerror("VPD: Creating node at %s@%"PRIx64" failed\n",
476 : : name, addr);
477 : 0 : goto next_entry;
478 : : }
479 : :
480 : : /* Add location code */
481 : 29 : slca_vpd_add_loc_code(node, be16_to_cpu(entry->my_index));
482 : : /* Add FRU label */
483 : 29 : dt_add_property(node, "fru-type", entry->fru_id, 2);
484 : 29 : dt_add_property_cells(node, "reg", addr);
485 : 29 : dt_add_property_cells(node, "#size-cells", 0);
486 : 29 : dt_add_property_cells(node, "#address-cells", 1);
487 : :
488 : 69 : next_entry:
489 : : /* Skip dups -- dups are contiguous */
490 : 69 : index += entry->nr_dups;
491 : : }
492 : : }
493 : :
494 : 11 : struct dt_node *dt_add_vpd_node(const struct HDIF_common_hdr *hdr,
495 : : int indx_fru, int indx_vpd)
496 : : {
497 : : const struct spira_fru_id *fru_id;
498 : : unsigned int fruvpd_sz, fru_id_sz;
499 : : const struct slca_entry *entry;
500 : : struct dt_node *dt_vpd, *node;
501 : : const void *fruvpd;
502 : : const char *name;
503 : : uint64_t addr;
504 : :
505 : 11 : fru_id = HDIF_get_idata(hdr, indx_fru, &fru_id_sz);
506 : 11 : if (!fru_id)
507 : 0 : return NULL;
508 : :
509 : 11 : fruvpd = HDIF_get_idata(hdr, indx_vpd, &fruvpd_sz);
510 : 11 : if (!CHECK_SPPTR(fruvpd))
511 : 0 : return NULL;
512 : :
513 : 11 : dt_vpd = dt_find_by_path(dt_root, "/vpd");
514 : 11 : if (!dt_vpd)
515 : 0 : return NULL;
516 : :
517 : 11 : entry = slca_get_entry(be16_to_cpu(fru_id->slca_index));
518 : 11 : if (!entry)
519 : 0 : return NULL;
520 : :
521 : 11 : name = vpd_map_name(entry->fru_id);
522 : 11 : addr = be16_to_cpu(entry->rsrc_id);
523 : : /* Get the node already created */
524 : 11 : node = dt_find_by_name_addr(dt_vpd, name, addr);
525 : : /*
526 : : * It is unlikely that node not found because vpd nodes have the
527 : : * corresponding slca entry which we would have used to populate the vpd
528 : : * tree during the 'first' pass above so that we just need to perform
529 : : * VINI parse and add the vpd data..
530 : : */
531 : 11 : if (!node)
532 : 0 : return NULL;
533 : :
534 : : /* Parse VPD fields, ensure that it has not been added already */
535 : 11 : if (vpd_valid(fruvpd, fruvpd_sz)
536 : 11 : && !dt_find_property(node, "ibm,vpd")) {
537 : 10 : dt_add_property(node, "ibm,vpd", fruvpd, fruvpd_sz);
538 : 10 : vpd_data_parse(node, fruvpd, fruvpd_sz);
539 : : }
540 : :
541 : 11 : return node;
542 : : }
543 : :
544 : 1 : static void dt_add_model_name(void)
545 : : {
546 : 1 : const char *model_name = NULL;
547 : : const struct machine_info *mi;
548 : : const struct iplparams_sysparams *p;
549 : : const struct HDIF_common_hdr *iplp;
550 : : const struct dt_property *model;
551 : :
552 : 1 : model = dt_find_property(dt_root, "model");
553 : :
554 : 1 : iplp = get_hdif(&spiras->ntuples.ipl_parms, "IPLPMS");
555 : 1 : if (!iplp)
556 : 0 : goto def_model;
557 : :
558 : 1 : p = HDIF_get_idata(iplp, IPLPARAMS_SYSPARAMS, NULL);
559 : 1 : if (!CHECK_SPPTR(p))
560 : 0 : goto def_model;
561 : :
562 : 1 : if (be16_to_cpu(iplp->version) >= 0x60)
563 : 0 : model_name = p->sys_type_str;
564 : :
565 : 1 : def_model:
566 : 1 : if ((!model_name || model_name[0] == '\0') && model) {
567 : 1 : mi = machine_info_lookup(model->prop);
568 : 1 : if (mi)
569 : 1 : model_name = mi->name;
570 : : }
571 : :
572 : 1 : if(model_name)
573 : 1 : dt_add_property_string(dt_root, "model-name", model_name);
574 : 1 : }
575 : :
576 : 0 : static void sysvpd_parse_opp(const void *sysvpd, unsigned int sysvpd_sz)
577 : : {
578 : : const char *v;
579 : : uint8_t sz;
580 : :
581 : 0 : v = vpd_find(sysvpd, sysvpd_sz, "OSYS", "MM", &sz);
582 : 0 : if (v)
583 : 0 : dt_add_prop_sanitize_val(dt_root, "model", v, sz);
584 : : else
585 : 0 : dt_add_property_string(dt_root, "model", "Unknown");
586 : :
587 : 0 : v = vpd_find(sysvpd, sysvpd_sz, "OSYS", "SS", &sz);
588 : 0 : if (v)
589 : 0 : dt_add_prop_sanitize_val(dt_root, "system-id", v, sz);
590 : : else
591 : 0 : dt_add_property_string(dt_root, "system-id", "Unknown");
592 : 0 : }
593 : :
594 : :
595 : 1 : static void sysvpd_parse_legacy(const void *sysvpd, unsigned int sysvpd_sz)
596 : : {
597 : : const char *model;
598 : : const char *system_id;
599 : : const char *brand;
600 : : uint8_t sz;
601 : :
602 : 1 : model = vpd_find(sysvpd, sysvpd_sz, "VSYS", "TM", &sz);
603 : 1 : if (model)
604 : 1 : dt_add_prop_sanitize_val(dt_root, "model", model, sz);
605 : : else
606 : 0 : dt_add_property_string(dt_root, "model", "Unknown");
607 : :
608 : 1 : system_id = vpd_find(sysvpd, sysvpd_sz, "VSYS", "SE", &sz);
609 : 1 : if (system_id)
610 : 1 : dt_add_prop_sanitize_val(dt_root, "system-id", system_id, sz);
611 : : else
612 : 0 : dt_add_property_string(dt_root, "system-id", "Unknown");
613 : :
614 : 1 : brand = vpd_find(sysvpd, sysvpd_sz, "VSYS", "BR", &sz);
615 : 1 : if (brand)
616 : 1 : dt_add_prop_sanitize_val(dt_root, "system-brand", brand, sz);
617 : : else
618 : 0 : dt_add_property_string(dt_root, "brand", "Unknown");
619 : 1 : }
620 : :
621 : 1 : static void sysvpd_parse(void)
622 : : {
623 : : const void *sysvpd;
624 : : unsigned int sysvpd_sz;
625 : : unsigned int fru_id_sz;
626 : : struct dt_node *dt_vpd;
627 : : const struct spira_fru_id *fru_id;
628 : : struct HDIF_common_hdr *sysvpd_hdr;
629 : :
630 : 1 : sysvpd_hdr = get_hdif(&spiras->ntuples.system_vpd, SYSVPD_HDIF_SIG);
631 : 1 : if (!sysvpd_hdr)
632 : 0 : return;
633 : :
634 : 1 : fru_id = HDIF_get_idata(sysvpd_hdr, SYSVPD_IDATA_FRU_ID, &fru_id_sz);
635 : 1 : if (!fru_id)
636 : 0 : return;
637 : :
638 : 1 : sysvpd = HDIF_get_idata(sysvpd_hdr, SYSVPD_IDATA_KW_VPD, &sysvpd_sz);
639 : 1 : if (!CHECK_SPPTR(sysvpd))
640 : 0 : return;
641 : :
642 : : /* Add system VPD */
643 : 1 : dt_vpd = dt_find_by_path(dt_root, "/vpd");
644 : 1 : if (dt_vpd) {
645 : 1 : dt_add_property(dt_vpd, "ibm,vpd", sysvpd, sysvpd_sz);
646 : 1 : slca_vpd_add_loc_code(dt_vpd, be16_to_cpu(fru_id->slca_index));
647 : : }
648 : :
649 : : /* Look for the new OpenPower "OSYS" first */
650 : 1 : if (vpd_find_record(sysvpd, sysvpd_sz, "OSYS", NULL))
651 : 0 : sysvpd_parse_opp(sysvpd, sysvpd_sz);
652 : : else
653 : 1 : sysvpd_parse_legacy(sysvpd, sysvpd_sz);
654 : :
655 : 1 : dt_add_model_name();
656 : : }
657 : :
658 : 1 : static void iokid_vpd_parse(const struct HDIF_common_hdr *iohub_hdr)
659 : : {
660 : : const struct HDIF_child_ptr *iokids;
661 : : const struct HDIF_common_hdr *iokid;
662 : : unsigned int i;
663 : :
664 : 1 : iokids = HDIF_child_arr(iohub_hdr, CECHUB_CHILD_IO_KIDS);
665 : 1 : if (!CHECK_SPPTR(iokids)) {
666 : 0 : prerror("VPD: No IOKID child array\n");
667 : 0 : return;
668 : : }
669 : :
670 : 2 : for (i = 0; i < be32_to_cpu(iokids->count); i++) {
671 : 1 : iokid = HDIF_child(iohub_hdr, iokids, i,
672 : : IOKID_FRU_HDIF_SIG);
673 : : /* IO KID VPD structure layout is similar to FRUVPD */
674 : 1 : if (iokid)
675 : 1 : dt_add_vpd_node(iokid,
676 : : FRUVPD_IDATA_FRU_ID, FRUVPD_IDATA_KW_VPD);
677 : : }
678 : : }
679 : :
680 : 1 : static void iohub_vpd_parse(void)
681 : : {
682 : : const struct HDIF_common_hdr *iohub_hdr;
683 : : const struct cechub_hub_fru_id *fru_id_data;
684 : : unsigned int i, vpd_sz, fru_id_sz;
685 : :
686 : 1 : if (!get_hdif(&spiras->ntuples.cec_iohub_fru, CECHUB_FRU_HDIF_SIG)) {
687 : 0 : prerror("VPD: Could not find IO HUB FRU data\n");
688 : 0 : return;
689 : : }
690 : :
691 : 2 : for_each_ntuple_idx(&spiras->ntuples.cec_iohub_fru, iohub_hdr,
692 : : i, CECHUB_FRU_HDIF_SIG) {
693 : :
694 : 1 : fru_id_data = HDIF_get_idata(iohub_hdr,
695 : : CECHUB_FRU_ID_DATA_AREA,
696 : : &fru_id_sz);
697 : :
698 : : /* P8, IO HUB is on processor card and we have a
699 : : * daughter card array
700 : : */
701 : 2 : if (fru_id_data &&
702 : 1 : be32_to_cpu(fru_id_data->card_type) == CECHUB_FRU_TYPE_CPU_CARD) {
703 : 1 : iokid_vpd_parse(iohub_hdr);
704 : 1 : continue;
705 : : }
706 : :
707 : 0 : if (HDIF_get_idata(iohub_hdr,
708 : : CECHUB_ASCII_KEYWORD_VPD, &vpd_sz))
709 : 0 : dt_add_vpd_node(iohub_hdr, CECHUB_FRU_ID_DATA,
710 : : CECHUB_ASCII_KEYWORD_VPD);
711 : : }
712 : : }
713 : :
714 : 6 : static void _vpd_parse(struct spira_ntuple tuple)
715 : : {
716 : : const struct HDIF_common_hdr *fruvpd_hdr;
717 : : unsigned int i;
718 : :
719 : 6 : if (!get_hdif(&tuple, FRUVPD_HDIF_SIG))
720 : 1 : return;
721 : :
722 : 10 : for_each_ntuple_idx(&tuple, fruvpd_hdr, i, FRUVPD_HDIF_SIG)
723 : 5 : dt_add_vpd_node(fruvpd_hdr,
724 : : FRUVPD_IDATA_FRU_ID, FRUVPD_IDATA_KW_VPD);
725 : : }
726 : :
727 : 1 : void vpd_parse(void)
728 : : {
729 : : const struct HDIF_common_hdr *fruvpd_hdr;
730 : :
731 : : /* System VPD uses the VSYS record, so its special */
732 : 1 : sysvpd_parse();
733 : :
734 : : /* Enclosure */
735 : 1 : _vpd_parse(spiras->ntuples.nt_enclosure_vpd);
736 : :
737 : : /* Backplane */
738 : 1 : _vpd_parse(spiras->ntuples.backplane_vpd);
739 : :
740 : : /* clock card -- does this use the FRUVPD sig? */
741 : 1 : _vpd_parse(spiras->ntuples.clock_vpd);
742 : :
743 : : /* Anchor card */
744 : 1 : _vpd_parse(spiras->ntuples.anchor_vpd);
745 : :
746 : : /* Op panel -- does this use the FRUVPD sig? */
747 : 1 : _vpd_parse(spiras->ntuples.op_panel_vpd);
748 : :
749 : : /* Misc CEC FRU */
750 : 1 : _vpd_parse(spiras->ntuples.misc_cec_fru_vpd);
751 : :
752 : : /* CEC IO HUB FRU */
753 : 1 : iohub_vpd_parse();
754 : :
755 : : /*
756 : : * SP subsystem -- while the rest of the SPINFO structure is
757 : : * different, the FRU ID data and pointer pair to keyword VPD
758 : : * are the same offset as a FRUVPD entry. So reuse it
759 : : */
760 : 1 : fruvpd_hdr = get_hdif(&spiras->ntuples.sp_subsys, SPSS_HDIF_SIG);
761 : 1 : if (fruvpd_hdr)
762 : 1 : dt_add_vpd_node(fruvpd_hdr,
763 : : FRUVPD_IDATA_FRU_ID, FRUVPD_IDATA_KW_VPD);
764 : 1 : }
|