Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2013-2017 IBM Corp. */
3 : :
4 : : #include <device.h>
5 : : #include "spira.h"
6 : : #include <cpu.h>
7 : : #include <vpd.h>
8 : : #include <ccan/str/str.h>
9 : : #include <interrupts.h>
10 : : #include <inttypes.h>
11 : : #include <phys-map.h>
12 : : #include <chip.h>
13 : : #include <ipmi.h>
14 : :
15 : : #include "hdata.h"
16 : :
17 : : enum sp_type {
18 : : SP_BAD = 0,
19 : : SP_UNKNOWN,
20 : : SP_FSP,
21 : : SP_BMC,
22 : : };
23 : :
24 : : static const char * const sp_names[] = {
25 : : "Broken", "Unknown", "FSP", "BMC",
26 : : };
27 : :
28 : 2 : static enum sp_type find_service_proc_type(const struct HDIF_common_hdr *spss,
29 : : int index)
30 : : {
31 : : const struct spss_sp_impl *sp_impl;
32 : : int hw_ver, sw_ver, flags;
33 : : enum sp_type sp_type;
34 : : bool functional, installed;
35 : :
36 : : /* Find an check the SP Implementation structure */
37 : 2 : sp_impl = HDIF_get_idata(spss, SPSS_IDATA_SP_IMPL, NULL);
38 : 2 : if (!CHECK_SPPTR(sp_impl)) {
39 : 0 : prerror("SP #%d: SPSS/SP_Implementation not found !\n", index);
40 : 0 : return SP_BAD;
41 : : }
42 : :
43 : 2 : hw_ver = be16_to_cpu(sp_impl->hw_version);
44 : 2 : sw_ver = be16_to_cpu(sp_impl->sw_version);
45 : 2 : flags = be16_to_cpu(sp_impl->func_flags);
46 : :
47 : 2 : switch (hw_ver) {
48 : 2 : case 0x1:
49 : : case 0x2: /* We only support FSP2 */
50 : 2 : sp_type = SP_FSP;
51 : 2 : break;
52 : 0 : case 0x3:
53 : 0 : sp_type = SP_BMC;
54 : 0 : break;
55 : 0 : default:
56 : 0 : sp_type = SP_UNKNOWN;
57 : : }
58 : :
59 : 2 : if (sp_type == SP_UNKNOWN)
60 : 0 : return SP_UNKNOWN;
61 : :
62 : 2 : installed = !!(flags & SPSS_SP_IMPL_FLAGS_INSTALLED);
63 : 2 : functional = !!(flags & SPSS_SP_IMPL_FLAGS_FUNCTIONAL);
64 : :
65 : 2 : if (!installed || !functional) {
66 : 0 : prerror("%s #%d not usable: %sinstalled, %sfunctional\n",
67 : : sp_names[sp_type], index,
68 : : installed ? "" : "not ",
69 : : functional ? "" : "not ");
70 : :
71 : 0 : return SP_BAD;
72 : : }
73 : :
74 : 2 : prlog(PR_INFO, "%s #%d: HW version %d, SW version %d, chip DD%d.%d\n",
75 : : sp_names[sp_type], index, hw_ver, sw_ver,
76 : : sp_impl->chip_version >> 4,
77 : : sp_impl->chip_version & 0xf);
78 : :
79 : 2 : return sp_type;
80 : : }
81 : :
82 : : /*
83 : : * Note on DT representation of the PSI links and FSPs:
84 : : *
85 : : * We create a XSCOM node for each PSI host bridge(one per chip),
86 : : *
87 : : * This is done in spira.c
88 : : *
89 : : * We do not create the /psi MMIO variant at this stage, it will
90 : : * be added by the psi driver in skiboot.
91 : : *
92 : : * We do not put the FSP(s) as children of these. Instead, we create
93 : : * a top-level /fsps node with the FSPs as children.
94 : : *
95 : : * Each FSP then has a "links" property which is an array of chip IDs
96 : : */
97 : :
98 : 1 : static struct dt_node *fsp_create_node(const void *spss, int i,
99 : : struct dt_node *parent)
100 : : {
101 : : const struct spss_sp_impl *sp_impl;
102 : : struct dt_node *node;
103 : :
104 : 1 : sp_impl = HDIF_get_idata(spss, SPSS_IDATA_SP_IMPL, NULL);
105 : :
106 : 1 : node = dt_new_addr(parent, "fsp", i);
107 : 1 : assert(node);
108 : :
109 : 1 : dt_add_property_cells(node, "reg", i);
110 : :
111 : 1 : if (be16_to_cpu(sp_impl->hw_version) == 1) {
112 : 0 : dt_add_property_strings(node, "compatible", "ibm,fsp",
113 : : "ibm,fsp1");
114 : : /* Offset into the FSP MMIO space where the mailbox
115 : : * registers are */
116 : : /* seen in the FSP1 spec */
117 : 0 : dt_add_property_cells(node, "reg-offset", 0xb0016000);
118 : 1 : } else if (be16_to_cpu(sp_impl->hw_version) == 2) {
119 : 1 : dt_add_property_strings(node, "compatible", "ibm,fsp",
120 : : "ibm,fsp2");
121 : 1 : dt_add_property_cells(node, "reg-offset", 0xb0011000);
122 : : }
123 : 1 : dt_add_property_cells(node, "hw-version", be16_to_cpu(sp_impl->hw_version));
124 : 1 : dt_add_property_cells(node, "sw-version", be16_to_cpu(sp_impl->sw_version));
125 : :
126 : 1 : if (be16_to_cpu(sp_impl->func_flags) & SPSS_SP_IMPL_FLAGS_PRIMARY)
127 : 1 : dt_add_property(node, "primary", NULL, 0);
128 : :
129 : 1 : return node;
130 : : }
131 : :
132 : 1 : static uint32_t fsp_create_link(const struct spss_iopath *iopath, int index,
133 : : int fsp_index)
134 : : {
135 : : struct dt_node *node;
136 : : const char *ststr;
137 : 1 : bool current = false;
138 : 1 : bool working = false;
139 : : uint32_t chip_id;
140 : :
141 : 1 : switch(be16_to_cpu(iopath->psi.link_status)) {
142 : 0 : case SPSS_IO_PATH_PSI_LINK_BAD_FRU:
143 : 0 : ststr = "Broken";
144 : 0 : break;
145 : 1 : case SPSS_IO_PATH_PSI_LINK_CURRENT:
146 : 1 : ststr = "Active";
147 : 1 : current = working = true;
148 : 1 : break;
149 : 0 : case SPSS_IO_PATH_PSI_LINK_BACKUP:
150 : 0 : ststr = "Backup";
151 : 0 : working = true;
152 : 0 : break;
153 : 0 : default:
154 : 0 : ststr = "Unknown";
155 : : }
156 : 1 : prlog(PR_DEBUG, "FSP #%d: IO PATH %d is %s PSI Link, GXHB at %" PRIx64 "\n",
157 : : fsp_index, index, ststr, be64_to_cpu(iopath->psi.gxhb_base));
158 : :
159 : 1 : chip_id = pcid_to_chip_id(be32_to_cpu(iopath->psi.proc_chip_id));
160 : 1 : node = dt_find_compatible_node_on_chip(dt_root, NULL, "ibm,psihb-x",
161 : : chip_id);
162 : 1 : if (!node) {
163 : 0 : prerror("FSP #%d: Can't find psihb node for link %d\n",
164 : : fsp_index, index);
165 : : } else {
166 : 1 : if (current)
167 : 1 : dt_add_property(node, "boot-link", NULL, 0);
168 : 1 : dt_add_property_strings(node, "status", working ? "ok" : "bad");
169 : : }
170 : :
171 : 1 : return chip_id;
172 : : }
173 : :
174 : 1 : static void fsp_create_links(const void *spss, int index,
175 : : struct dt_node *fsp_node)
176 : : {
177 : 1 : __be32 *links = NULL;
178 : 1 : unsigned int i, lp, lcount = 0;
179 : : int count;
180 : :
181 : 1 : count = HDIF_get_iarray_size(spss, SPSS_IDATA_SP_IOPATH);
182 : 1 : if (count < 0) {
183 : 0 : prerror("FSP #%d: Can't find IO PATH array size !\n", index);
184 : 0 : return;
185 : : }
186 : 1 : prlog(PR_DEBUG, "FSP #%d: Found %d IO PATH\n", index, count);
187 : :
188 : : /* Iterate all links */
189 : 2 : for (i = 0; i < count; i++) {
190 : : const struct spss_iopath *iopath;
191 : : unsigned int iopath_sz;
192 : : uint32_t chip;
193 : :
194 : 1 : iopath = HDIF_get_iarray_item(spss, SPSS_IDATA_SP_IOPATH,
195 : : i, &iopath_sz);
196 : 1 : if (!CHECK_SPPTR(iopath)) {
197 : 0 : prerror("FSP #%d: Can't find IO PATH %d\n", index, i);
198 : 0 : break;
199 : : }
200 : 1 : if (be16_to_cpu(iopath->iopath_type) != SPSS_IOPATH_TYPE_PSI) {
201 : 0 : prerror("FSP #%d: Unsupported IO PATH %d type 0x%04x\n",
202 : : index, i, iopath->iopath_type);
203 : 0 : continue;
204 : : }
205 : :
206 : 1 : chip = fsp_create_link(iopath, i, index);
207 : 1 : lp = lcount++;
208 : 1 : links = realloc(links, 4 * lcount);
209 : 1 : links[lp] = cpu_to_be32(chip);
210 : : }
211 : 1 : if (links)
212 : 1 : dt_add_property(fsp_node, "ibm,psi-links", links, lcount * 4);
213 : :
214 : 1 : free(links);
215 : : }
216 : :
217 : 0 : static struct dt_node *add_lpc_io_node(struct dt_node *parent,
218 : : const char *name, u32 offset, u32 size)
219 : : {
220 : : struct dt_node *n;
221 : : char buffer[32];
222 : :
223 : : /*
224 : : * LPC bus addresses have strange DT names, they have the
225 : : * Bus address space embedded into the unit address e.g.
226 : : * serial@i3f8 - refers to offset 0x3f8 in the IO space
227 : : */
228 : :
229 : 0 : snprintf(buffer, sizeof(buffer), "%s@i%x", name, offset);
230 : 0 : n = dt_new(parent, buffer);
231 : 0 : assert(n);
232 : :
233 : : /* first address cell of 1 indicates the LPC IO space */
234 : 0 : dt_add_property_cells(n, "reg", 1, offset, size);
235 : :
236 : 0 : return n;
237 : : }
238 : :
239 : 0 : static void add_uart(const struct spss_iopath *iopath, struct dt_node *lpc)
240 : : {
241 : : struct dt_node *serial;
242 : : u64 base;
243 : :
244 : : /* XXX: The spec says this is supposed to be a MMIO address.
245 : : * However, in practice we get an LPC IO Space offset.
246 : : */
247 : 0 : base = be64_to_cpu(iopath->lpc.uart_base);
248 : :
249 : 0 : serial = add_lpc_io_node(lpc, "serial", base,
250 : 0 : be32_to_cpu(iopath->lpc.uart_size));
251 : :
252 : 0 : dt_add_property_string(serial, "compatible", "ns16550");
253 : :
254 : 0 : dt_add_property_cells(serial, "current-speed",
255 : : be32_to_cpu(iopath->lpc.uart_baud));
256 : 0 : dt_add_property_cells(serial, "clock-frequency",
257 : : be32_to_cpu(iopath->lpc.uart_clk));
258 : 0 : dt_add_property_cells(serial, "interrupts",
259 : : iopath->lpc.uart_int_number);
260 : 0 : dt_add_property_string(serial, "device_type", "serial");
261 : :
262 : :
263 : 0 : prlog(PR_DEBUG, "LPC UART: base addr = %#" PRIx64" (%#" PRIx64 ") size = %#x clk = %u, baud = %u\n",
264 : : be64_to_cpu(iopath->lpc.uart_base),
265 : : base,
266 : : be32_to_cpu(iopath->lpc.uart_size),
267 : : be32_to_cpu(iopath->lpc.uart_clk),
268 : : be32_to_cpu(iopath->lpc.uart_baud));
269 : 0 : }
270 : :
271 : 0 : static void add_chip_id_to_sensors(struct dt_node *sensor_node, uint32_t slca_index)
272 : : {
273 : : unsigned int i;
274 : : const void *hdif;
275 : : const struct slca_entry *slca;
276 : : const struct spira_fru_id *fru_id;
277 : : const struct sppcrd_chip_info *cinfo;
278 : :
279 : 0 : slca = slca_get_entry(slca_index);
280 : 0 : if (slca == NULL) {
281 : 0 : prlog(PR_WARNING, "SENSORS: Invalid slca index\n");
282 : 0 : return;
283 : : }
284 : :
285 : 0 : for_each_ntuple_idx(&spiras->ntuples.proc_chip, hdif, i, SPPCRD_HDIF_SIG) {
286 : 0 : fru_id = HDIF_get_idata(hdif, SPPCRD_IDATA_FRU_ID, NULL);
287 : 0 : if (!fru_id)
288 : 0 : return;
289 : :
290 : 0 : if (fru_id->rsrc_id != slca->rsrc_id)
291 : 0 : continue;
292 : :
293 : 0 : cinfo = HDIF_get_idata(hdif, SPPCRD_IDATA_CHIP_INFO, NULL);
294 : 0 : if (!CHECK_SPPTR(cinfo)) {
295 : 0 : prlog(PR_ERR, "SENSORS: Bad ChipID data %d\n", i);
296 : 0 : return;
297 : : }
298 : :
299 : 0 : dt_add_property_cells(sensor_node,
300 : : "ibm,chip-id", get_xscom_id(cinfo));
301 : 0 : return;
302 : : }
303 : : }
304 : :
305 : 0 : static void add_ipmi_sensors(struct dt_node *bmc_node)
306 : : {
307 : : int i;
308 : : const struct HDIF_common_hdr *hdif_sensor;
309 : : const struct ipmi_sensors *ipmi_sensors;
310 : : struct dt_node *sensors_node, *sensor_node;
311 : :
312 : 0 : hdif_sensor = get_hdif(&spiras->ntuples.ipmi_sensor, IPMI_SENSORS_HDIF_SIG);
313 : 0 : if (!hdif_sensor) {
314 : 0 : prlog(PR_DEBUG, "SENSORS: Missing IPMI sensors mappings tuple\n");
315 : 0 : return;
316 : : }
317 : :
318 : 0 : ipmi_sensors = HDIF_get_idata(hdif_sensor, IPMI_SENSORS_IDATA_SENSORS, NULL);
319 : 0 : if (!ipmi_sensors) {
320 : 0 : prlog(PR_DEBUG, "SENSORS: bad data\n");
321 : 0 : return;
322 : : }
323 : :
324 : 0 : sensors_node = dt_new(bmc_node, "sensors");
325 : 0 : assert(sensors_node);
326 : :
327 : 0 : dt_add_property_cells(sensors_node, "#address-cells", 1);
328 : 0 : dt_add_property_cells(sensors_node, "#size-cells", 0);
329 : :
330 : 0 : for (i = 0; i < be32_to_cpu(ipmi_sensors->count); i++) {
331 : 0 : if(dt_find_by_name_addr(sensors_node, "sensor",
332 : 0 : ipmi_sensors->data[i].id)) {
333 : 0 : prlog(PR_WARNING, "SENSORS: Duplicate sensor ID : %x\n",
334 : : ipmi_sensors->data[i].id);
335 : 0 : continue;
336 : : }
337 : :
338 : : /* We support only < MAX_IPMI_SENSORS sensors */
339 : 0 : if (!(ipmi_sensors->data[i].type < MAX_IPMI_SENSORS))
340 : 0 : continue;
341 : :
342 : 0 : sensor_node = dt_new_addr(sensors_node, "sensor",
343 : 0 : ipmi_sensors->data[i].id);
344 : 0 : assert(sensor_node);
345 : 0 : dt_add_property_string(sensor_node, "compatible", "ibm,ipmi-sensor");
346 : 0 : dt_add_property_cells(sensor_node, "reg", ipmi_sensors->data[i].id);
347 : 0 : dt_add_property_cells(sensor_node, "ipmi-sensor-type",
348 : : ipmi_sensors->data[i].type);
349 : :
350 : 0 : add_chip_id_to_sensors(sensor_node,
351 : 0 : be32_to_cpu(ipmi_sensors->data[i].slca_index));
352 : : }
353 : : }
354 : :
355 : 0 : static void bmc_create_node(const struct HDIF_common_hdr *sp)
356 : : {
357 : : struct dt_node *bmc_node;
358 : : u32 fw_bar, io_bar, mem_bar, internal_bar, mctp_base;
359 : : const struct spss_iopath *iopath;
360 : : const struct spss_sp_impl *sp_impl;
361 : : struct dt_node *lpcm, *lpc, *n;
362 : : u64 lpcm_base, lpcm_end;
363 : : uint32_t chip_id;
364 : : uint32_t topology_idx;
365 : : int size;
366 : :
367 : 0 : bmc_node = dt_new(dt_root, "bmc");
368 : 0 : assert(bmc_node);
369 : :
370 : 0 : dt_add_property_cells(bmc_node, "#address-cells", 1);
371 : 0 : dt_add_property_cells(bmc_node, "#size-cells", 0);
372 : :
373 : : /* Add sensor info under /bmc */
374 : 0 : if (proc_gen < proc_gen_p10)
375 : 0 : add_ipmi_sensors(bmc_node);
376 : :
377 : 0 : sp_impl = HDIF_get_idata(sp, SPSS_IDATA_SP_IMPL, &size);
378 : 0 : if (CHECK_SPPTR(sp_impl) && (size > 8)) {
379 : 0 : dt_add_property_strings(bmc_node, "compatible", sp_impl->sp_family);
380 : 0 : prlog(PR_INFO, "SP Family is %s\n", sp_impl->sp_family);
381 : : }
382 : :
383 : 0 : iopath = HDIF_get_iarray_item(sp, SPSS_IDATA_SP_IOPATH, 0, NULL);
384 : :
385 : 0 : if (be16_to_cpu(iopath->iopath_type) != SPSS_IOPATH_TYPE_LPC) {
386 : 0 : prerror("BMC: Non-LPC IOPATH, this is probably broken\n");
387 : 0 : return;
388 : : }
389 : :
390 : : /*
391 : : * For now we only instantiate the LPC node for the LPC that is used
392 : : * for Host <-> BMC comms. The secondary LPCs can be skipped.
393 : : */
394 : 0 : if (be16_to_cpu(iopath->lpc.link_status) != LPC_STATUS_ACTIVE)
395 : 0 : return;
396 : :
397 : : #define GB (1024ul * 1024ul * 1024ul)
398 : : /*
399 : : * convert the hdat chip ID the HW chip id so we get the right
400 : : * phys map offset
401 : : */
402 : 0 : chip_id = pcid_to_chip_id(be32_to_cpu(iopath->lpc.chip_id));
403 : 0 : topology_idx = pcid_to_topology_idx(be32_to_cpu(iopath->lpc.chip_id));
404 : :
405 : 0 : __phys_map_get(topology_idx, chip_id, LPC_BUS, 0, &lpcm_base, NULL);
406 : 0 : lpcm = dt_new_addr(dt_root, "lpcm-opb", lpcm_base);
407 : 0 : assert(lpcm);
408 : :
409 : 0 : dt_add_property_cells(lpcm, "#address-cells", 1);
410 : 0 : dt_add_property_cells(lpcm, "#size-cells", 1);
411 : 0 : dt_add_property_strings(lpcm, "compatible",
412 : : "ibm,power9-lpcm-opb", "simple-bus");
413 : 0 : dt_add_property_u64s(lpcm, "reg", lpcm_base, 0x100000000ul);
414 : :
415 : 0 : dt_add_property_cells(lpcm, "ibm,chip-id", chip_id);
416 : :
417 : : /* Setup the ranges for the MMIO LPC */
418 : 0 : lpcm_end = lpcm_base + 2 * GB;
419 : 0 : dt_add_property_cells(lpcm, "ranges",
420 : : 0x00000000, hi32(lpcm_base), lo32(lpcm_base), 2 * GB,
421 : : 0x80000000, hi32(lpcm_end), lo32(lpcm_end), 2 * GB);
422 : :
423 : : /*
424 : : * Despite the name the "BAR" values provided through the HDAT are
425 : : * the base addresses themselves rather than the BARs
426 : : */
427 : 0 : fw_bar = be32_to_cpu(iopath->lpc.firmware_bar);
428 : 0 : mem_bar = be32_to_cpu(iopath->lpc.memory_bar);
429 : 0 : io_bar = be32_to_cpu(iopath->lpc.io_bar);
430 : 0 : internal_bar = be32_to_cpu(iopath->lpc.internal_bar);
431 : 0 : mctp_base = be32_to_cpu(iopath->lpc.mctp_base);
432 : :
433 : 0 : prlog(PR_DEBUG, "LPC: IOPATH chip id = %x\n", chip_id);
434 : 0 : prlog(PR_DEBUG, "LPC: FW BAR = %#x\n", fw_bar);
435 : 0 : prlog(PR_DEBUG, "LPC: MEM BAR = %#x\n", mem_bar);
436 : 0 : prlog(PR_DEBUG, "LPC: IO BAR = %#x\n", io_bar);
437 : 0 : prlog(PR_DEBUG, "LPC: Internal BAR = %#x\n", internal_bar);
438 : 0 : if (proc_gen >= proc_gen_p10) {
439 : : /* MCTP is part of FW BAR */
440 : 0 : prlog(PR_DEBUG, "LPC: MCTP base = %#x\n", mctp_base);
441 : : }
442 : :
443 : : /*
444 : : * The internal address space BAR actually points to the LPC master
445 : : * registers. So we "fix" it by masking off the low bits.
446 : : *
447 : : * XXX: we probably need separate base addresses for all these things
448 : : */
449 : 0 : internal_bar &= 0xf0000000;
450 : :
451 : : /* Add the various internal bus devices */
452 : 0 : n = dt_new_addr(lpcm, "opb-master", internal_bar + 0x10000);
453 : 0 : dt_add_property_string(n, "compatible", "ibm,power9-lpcm-opb-master");
454 : 0 : dt_add_property_cells(n, "reg", internal_bar + 0x10000, 0x60);
455 : :
456 : 0 : n = dt_new_addr(lpcm, "opb-arbiter", internal_bar + 0x11000);
457 : 0 : dt_add_property_string(n, "compatible", "ibm,power9-lpcm-opb-arbiter");
458 : 0 : dt_add_property_cells(n, "reg", internal_bar + 0x11000, 0x8);
459 : :
460 : 0 : n = dt_new_addr(lpcm, "lpc-controller", internal_bar + 0x12000);
461 : 0 : dt_add_property_string(n, "compatible", "ibm,power9-lpc-controller");
462 : 0 : dt_add_property_cells(n, "reg", internal_bar + 0x12000, 0x100);
463 : :
464 : : /*
465 : : * FIXME: lpc@0 might not be accurate, but i'm pretty sure
466 : : * lpc@f0000000 isn't right either.
467 : : */
468 : 0 : lpc = dt_new_addr(lpcm, "lpc", 0x0);
469 : 0 : dt_add_property_cells(lpc, "#address-cells", 2);
470 : 0 : dt_add_property_cells(lpc, "#size-cells", 1);
471 : 0 : dt_add_property_strings(lpc, "compatible",
472 : : "ibm,power9-lpc", "ibm,power8-lpc");
473 : :
474 : 0 : dt_add_property_cells(lpc, "ranges",
475 : : 0, 0, mem_bar, 0x10000000, /* MEM space */
476 : : 1, 0, io_bar, 0x00010000, /* IO space */
477 : : /* we don't expose the internal space */
478 : : 3, 0, fw_bar, 0x10000000 /* FW space */
479 : : );
480 : :
481 : 0 : add_uart(iopath, lpc);
482 : :
483 : : /* BT device info isn't currently populated */
484 : 0 : prlog(PR_DEBUG, "LPC: BT [%#"PRIx64", %#x] sms_int: %u, bmc_int: %u\n",
485 : : iopath->lpc.bt_base, iopath->lpc.bt_size,
486 : : iopath->lpc.bt_sms_int_num, iopath->lpc.bt_bmc_response_int_num
487 : : );
488 : : }
489 : :
490 : : /*
491 : : * Search for and instanciate BMC nodes. This is mostly the same as fsp_parse()
492 : : * below, but it can be called earlier since BMCs don't depend on the psihb
493 : : * nodes being added.
494 : : */
495 : 1 : void bmc_parse(void)
496 : : {
497 : 1 : bool found = false;
498 : : const void *sp;
499 : : int i;
500 : :
501 : 1 : sp = get_hdif(&spiras->ntuples.sp_subsys, SPSS_HDIF_SIG);
502 : 1 : if (!sp)
503 : 0 : return;
504 : :
505 : 2 : for_each_ntuple_idx(&spiras->ntuples.sp_subsys, sp, i, SPSS_HDIF_SIG) {
506 : 1 : if (find_service_proc_type(sp, i) == SP_BMC) {
507 : 0 : bmc_create_node(sp);
508 : 0 : found = true;
509 : : }
510 : : }
511 : :
512 : 1 : if (found)
513 : 0 : early_uart_init();
514 : : }
515 : :
516 : 1 : void fsp_parse(void)
517 : : {
518 : 1 : struct dt_node *fsp_root = NULL, *fsp_node;
519 : : const void *sp;
520 : : int index;
521 : :
522 : : /* Find SPSS tuple in SPIRA */
523 : 1 : sp = get_hdif(&spiras->ntuples.sp_subsys, SPSS_HDIF_SIG);
524 : 1 : if (!sp) {
525 : 0 : prlog(PR_WARNING, "HDAT: No FSP/BMC found!\n");
526 : 0 : return;
527 : : }
528 : :
529 : 2 : for_each_ntuple_idx(&spiras->ntuples.sp_subsys, sp, index, SPSS_HDIF_SIG) {
530 : 1 : switch (find_service_proc_type(sp, index)) {
531 : 1 : case SP_FSP:
532 : 1 : if (!fsp_root) {
533 : 1 : fsp_root = dt_new(dt_root, "fsps");
534 : 1 : assert(fsp_root);
535 : :
536 : 1 : dt_add_property_cells(fsp_root,
537 : : "#address-cells", 1);
538 : 1 : dt_add_property_cells(fsp_root,
539 : : "#size-cells", 0);
540 : : }
541 : :
542 : 1 : fsp_node = fsp_create_node(sp, index, fsp_root);
543 : 1 : if (fsp_node)
544 : 1 : fsp_create_links(sp, index, fsp_node);
545 : :
546 : 1 : break;
547 : :
548 : 0 : case SP_BMC:
549 : : /* Handled above */
550 : 0 : break;
551 : :
552 : 0 : case SP_BAD:
553 : 0 : break;
554 : :
555 : 0 : default:
556 : 0 : prerror("SP #%d: This service processor is not supported\n", index);
557 : 0 : break;
558 : : }
559 : : }
560 : : }
|