Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2013-2019 IBM Corp. */
3 : :
4 : : #include <skiboot.h>
5 : : #include "spira.h"
6 : : #include <cpu.h>
7 : : #include <fsp.h>
8 : : #include <opal.h>
9 : : #include <ccan/str/str.h>
10 : : #include <ccan/array_size/array_size.h>
11 : : #include <device.h>
12 : : #include <vpd.h>
13 : : #include <inttypes.h>
14 : : #include <string.h>
15 : :
16 : : #include "hdata.h"
17 : :
18 : 1 : static bool io_get_lx_info(const void *kwvpd, unsigned int kwvpd_sz,
19 : : int lx_idx, struct dt_node *hn)
20 : : {
21 : : const void *lxr;
22 : : char recname[5];
23 : 1 : beint32_t lxrbuf[2] = { 0, 0 };
24 : :
25 : : /* Find LXRn, where n is the index passed in*/
26 : 1 : strcpy(recname, "LXR0");
27 : 1 : recname[3] += lx_idx;
28 : 1 : lxr = vpd_find(kwvpd, kwvpd_sz, recname, "LX", NULL);
29 : 1 : if (!lxr) {
30 : : /* Not found, try VINI */
31 : 0 : lxr = vpd_find(kwvpd, kwvpd_sz, "VINI",
32 : : "LX", NULL);
33 : 0 : if (lxr)
34 : 0 : lx_idx = VPD_LOAD_LXRN_VINI;
35 : : }
36 : 1 : if (!lxr) {
37 : 0 : prlog(PR_DEBUG, "CEC: LXR%x not found !\n", lx_idx);
38 : 0 : return false;
39 : : }
40 : :
41 : 1 : memcpy(lxrbuf, lxr, sizeof(beint32_t)*2);
42 : :
43 : 1 : prlog(PR_DEBUG, "CEC: LXRn=%d LXR=%08x%08x\n", lx_idx, be32_to_cpu(lxrbuf[0]), be32_to_cpu(lxrbuf[1]));
44 : 1 : prlog(PR_DEBUG, "CEC: LX Info added to %llx\n", (long long)hn);
45 : :
46 : : /* Add the LX info */
47 : 1 : if (!dt_has_node_property(hn, "ibm,vpd-lx-info", NULL)) {
48 : 1 : dt_add_property_cells(hn, "ibm,vpd-lx-info",
49 : : lx_idx,
50 : : be32_to_cpu(lxrbuf[0]),
51 : : be32_to_cpu(lxrbuf[1]));
52 : : }
53 : :
54 : 1 : return true;
55 : : }
56 : :
57 : :
58 : 5 : static void io_get_loc_code(const void *sp_iohubs, struct dt_node *hn, const char *prop_name)
59 : : {
60 : : const struct spira_fru_id *fru_id;
61 : : unsigned int fru_id_sz;
62 : : char loc_code[LOC_CODE_SIZE + 1];
63 : : const char *slca_loc_code;
64 : :
65 : : /* Find SLCA Index */
66 : 5 : fru_id = HDIF_get_idata(sp_iohubs, CECHUB_FRU_ID_DATA, &fru_id_sz);
67 : 5 : if (fru_id) {
68 : 5 : memset(loc_code, 0, sizeof(loc_code));
69 : :
70 : : /* Find LOC Code from SLCA Index */
71 : 5 : slca_loc_code = slca_get_loc_code_index(be16_to_cpu(fru_id->slca_index));
72 : 5 : if (slca_loc_code) {
73 : 5 : strncpy(loc_code, slca_loc_code, LOC_CODE_SIZE);
74 : 5 : if (!dt_has_node_property(hn, prop_name, NULL)) {
75 : 5 : dt_add_property(hn, prop_name, loc_code,
76 : 5 : strlen(loc_code) + 1);
77 : : }
78 : 5 : prlog(PR_DEBUG, "CEC: %s: %s (SLCA rsrc 0x%x)\n",
79 : : prop_name, loc_code,
80 : : be16_to_cpu(fru_id->rsrc_id));
81 : : } else {
82 : 0 : prlog(PR_DEBUG, "CEC: SLCA Loc not found: "
83 : : "index %d\n", fru_id->slca_index);
84 : : }
85 : : } else {
86 : 0 : prlog(PR_DEBUG, "CEC: Hub FRU ID not found...\n");
87 : : }
88 : 5 : }
89 : :
90 : 4 : static struct dt_node *io_add_phb3(const struct cechub_io_hub *hub,
91 : : const struct HDIF_common_hdr *sp_iohubs,
92 : : unsigned int index, struct dt_node *xcom,
93 : : unsigned int pe_xscom,
94 : : unsigned int pci_xscom,
95 : : unsigned int spci_xscom)
96 : : {
97 : : struct dt_node *pbcq;
98 : : unsigned int hdif_vers;
99 : :
100 : : /* Get HDIF version */
101 : 4 : hdif_vers = be16_to_cpu(sp_iohubs->version);
102 : :
103 : : /* Create PBCQ node under xscom */
104 : 4 : pbcq = dt_new_addr(xcom, "pbcq", pe_xscom);
105 : 4 : if (!pbcq)
106 : 0 : return NULL;
107 : :
108 : : /* "reg" property contains in order the PE, PCI and SPCI XSCOM
109 : : * addresses
110 : : */
111 : 4 : dt_add_property_cells(pbcq, "reg",
112 : : pe_xscom, 0x20,
113 : : pci_xscom, 0x05,
114 : : spci_xscom, 0x15);
115 : :
116 : : /* A couple more things ... */
117 : 4 : dt_add_property_strings(pbcq, "compatible", "ibm,power8-pbcq");
118 : 4 : dt_add_property_cells(pbcq, "ibm,phb-index", index);
119 : 4 : dt_add_property_cells(pbcq, "ibm,hub-id", be16_to_cpu(hub->hub_num));
120 : :
121 : : /* The loc code of the PHB itself is different from the base
122 : : * loc code of the slots (It's actually the DCM's loc code).
123 : : */
124 : 4 : io_get_loc_code(sp_iohubs, pbcq, "ibm,loc-code");
125 : :
126 : : /* We indicate that this is an IBM setup, which means that
127 : : * the presence detect A/B bits are meaningful. So far we
128 : : * don't know whether they make any sense on customer setups
129 : : * so we only set that when booting with HDAT
130 : : */
131 : 4 : dt_add_property(pbcq, "ibm,use-ab-detect", NULL, 0);
132 : :
133 : : /* HDAT spec has these in version 0x6A and later */
134 : 4 : if (hdif_vers >= 0x6a) {
135 : 4 : u64 eq0 = be64_to_cpu(hub->phb_lane_eq[index][0]);
136 : 4 : u64 eq1 = be64_to_cpu(hub->phb_lane_eq[index][1]);
137 : 4 : u64 eq2 = be64_to_cpu(hub->phb_lane_eq[index][2]);
138 : 4 : u64 eq3 = be64_to_cpu(hub->phb_lane_eq[index][3]);
139 : :
140 : 4 : dt_add_property_u64s(pbcq, "ibm,lane-eq", eq0, eq1, eq2, eq3);
141 : : }
142 : :
143 : : /* Currently we only create a PBCQ node, the actual PHB nodes
144 : : * will be added by sapphire later on.
145 : : */
146 : 4 : return pbcq;
147 : : }
148 : :
149 : 0 : static struct dt_node *add_pec_stack(const struct cechub_io_hub *hub,
150 : : struct dt_node *pbcq, int stack_index,
151 : : int phb_index, u8 active_phbs)
152 : : {
153 : : struct dt_node *stack;
154 : : const char *compat;
155 : : u64 eq[12];
156 : : u8 *ptr;
157 : : int i;
158 : :
159 : 0 : stack = dt_new_addr(pbcq, "stack", stack_index);
160 : 0 : assert(stack);
161 : :
162 : 0 : if (proc_gen == proc_gen_p9)
163 : 0 : compat = "ibm,power9-phb-stack";
164 : : else
165 : 0 : compat = "ibm,power10-phb-stack";
166 : :
167 : 0 : dt_add_property_cells(stack, "reg", stack_index);
168 : 0 : dt_add_property_cells(stack, "ibm,phb-index", phb_index);
169 : 0 : dt_add_property_string(stack, "compatible", compat);
170 : :
171 : : /* XXX: This should probably just return if the PHB is disabled
172 : : * rather than adding the extra properties.
173 : : */
174 : :
175 : 0 : if (active_phbs & (0x80 >> phb_index))
176 : 0 : dt_add_property_string(stack, "status", "okay");
177 : : else
178 : 0 : dt_add_property_string(stack, "status", "disabled");
179 : :
180 : 0 : for (i = 0; i < 4; i++) /* gen 3 eq settings */
181 : 0 : eq[i] = be64_to_cpu(hub->phb_lane_eq[phb_index][i]);
182 : 0 : for (i = 0; i < 4; i++) /* gen 4 eq settings */
183 : 0 : eq[i+4] = be64_to_cpu(hub->phb4_lane_eq[phb_index][i]);
184 : 0 : for (i = 0; i < 4; i++) /* gen 5 eq settings */
185 : 0 : eq[i+8] = be64_to_cpu(hub->phb5_lane_eq[phb_index][i]);
186 : :
187 : : /* Lane-eq settings are packed 2 bytes per lane for 16 lanes
188 : : * On P9 DD2 and P10, 1 byte per lane is used in the hardware
189 : : */
190 : :
191 : : /* Repack 2 byte lane settings into 1 byte for gen 4 & 5 */
192 : 0 : ptr = (u8 *)&eq[4];
193 : 0 : for (i = 0; i < 32; i++)
194 : 0 : ptr[i] = ptr[2*i];
195 : :
196 : 0 : if (proc_gen == proc_gen_p9)
197 : 0 : dt_add_property_u64s(stack, "ibm,lane-eq",
198 : : eq[0], eq[1], eq[2], eq[3],
199 : : eq[4], eq[5]);
200 : : else
201 : 0 : dt_add_property_u64s(stack, "ibm,lane-eq",
202 : : eq[0], eq[1], eq[2], eq[3],
203 : : eq[4], eq[5],
204 : : eq[6], eq[7]);
205 : 0 : return stack;
206 : : }
207 : :
208 : : /* Add PHB4 on p9, PHB5 on p10 */
209 : 0 : static struct dt_node *io_add_phb4(const struct cechub_io_hub *hub,
210 : : const struct HDIF_common_hdr *sp_iohubs,
211 : : struct dt_node *xcom,
212 : : unsigned int pec_index,
213 : : int stacks,
214 : : int phb_base)
215 : : {
216 : : struct dt_node *pbcq;
217 : 0 : uint8_t active_phb_mask = hub->fab_br0_pdt;
218 : : uint32_t pe_xscom;
219 : : uint32_t pci_xscom;
220 : : const char *compat;
221 : : int i;
222 : :
223 : 0 : if (proc_gen == proc_gen_p9) {
224 : 0 : pe_xscom = 0x4010c00 + (pec_index * 0x0000400);
225 : 0 : pci_xscom = 0xd010800 + (pec_index * 0x1000000);
226 : 0 : compat = "ibm,power9-pbcq";
227 : : } else {
228 : 0 : pe_xscom = 0x3011800 - (pec_index * 0x1000000);
229 : 0 : pci_xscom = 0x8010800 + (pec_index * 0x1000000);
230 : 0 : compat = "ibm,power10-pbcq";
231 : : }
232 : :
233 : : /* Create PBCQ node under xscom */
234 : 0 : pbcq = dt_new_addr(xcom, "pbcq", pe_xscom);
235 : 0 : if (!pbcq)
236 : 0 : return NULL;
237 : :
238 : : /* "reg" property contains (in order) the PE and PCI XSCOM addresses */
239 : 0 : dt_add_property_cells(pbcq, "reg",
240 : : pe_xscom, 0x100,
241 : : pci_xscom, 0x200);
242 : :
243 : : /* The hubs themselves go under the stacks */
244 : 0 : dt_add_property_strings(pbcq, "compatible", compat);
245 : 0 : dt_add_property_cells(pbcq, "ibm,pec-index", pec_index);
246 : 0 : dt_add_property_cells(pbcq, "#address-cells", 1);
247 : 0 : dt_add_property_cells(pbcq, "#size-cells", 0);
248 : :
249 : 0 : for (i = 0; i < stacks; i++)
250 : 0 : add_pec_stack(hub, pbcq, i, phb_base + i, active_phb_mask);
251 : :
252 : 0 : dt_add_property_cells(pbcq, "ibm,hub-id", be16_to_cpu(hub->hub_num));
253 : :
254 : : /* The loc code of the PHB itself is different from the base
255 : : * loc code of the slots (It's actually the DCM's loc code).
256 : : */
257 : 0 : io_get_loc_code(sp_iohubs, pbcq, "ibm,loc-code");
258 : :
259 : 0 : prlog(PR_INFO, "CEC: Added PBCQ %d with %d stacks\n",
260 : : pec_index, stacks);
261 : :
262 : : /* the actual PHB nodes created later on by skiboot */
263 : 0 : return pbcq;
264 : : }
265 : :
266 : 2 : static struct dt_node *io_add_p8(const struct cechub_io_hub *hub,
267 : : const struct HDIF_common_hdr *sp_iohubs)
268 : : {
269 : : struct dt_node *xscom;
270 : : unsigned int i, chip_id;
271 : :
272 : 2 : chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
273 : :
274 : 2 : prlog(PR_INFO, "CEC: HW CHIP=0x%x, HW TOPO=0x%04x\n", chip_id,
275 : : be16_to_cpu(hub->hw_topology));
276 : :
277 : 2 : xscom = find_xscom_for_chip(chip_id);
278 : 2 : if (!xscom) {
279 : 0 : prerror("P8: Can't find XSCOM for chip %d\n", chip_id);
280 : 0 : return NULL;
281 : : }
282 : :
283 : : /* Create PHBs, max 3 */
284 : 8 : for (i = 0; i < 3; i++) {
285 : 6 : if (hub->fab_br0_pdt & (0x80 >> i))
286 : : /* XSCOM addresses are the same on Murano and Venice */
287 : 4 : io_add_phb3(hub, sp_iohubs, i, xscom,
288 : 4 : 0x02012000 + (i * 0x400),
289 : 4 : 0x09012000 + (i * 0x400),
290 : 4 : 0x09013c00 + (i * 0x40));
291 : : }
292 : :
293 : : /* HACK: We return the XSCOM device for the VPD info */
294 : 2 : return xscom;
295 : : }
296 : :
297 : : /* Add PBCQs for p9/p10 */
298 : 0 : static struct dt_node *io_add_p9(const struct cechub_io_hub *hub,
299 : : const struct HDIF_common_hdr *sp_iohubs)
300 : : {
301 : : struct dt_node *xscom;
302 : : unsigned int chip_id;
303 : :
304 : 0 : chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
305 : :
306 : 0 : prlog(PR_INFO, "CEC: HW CHIP=0x%x, HW TOPO=0x%04x\n", chip_id,
307 : : be16_to_cpu(hub->hw_topology));
308 : :
309 : 0 : xscom = find_xscom_for_chip(chip_id);
310 : 0 : if (!xscom) {
311 : 0 : prerror("IOHUB: Can't find XSCOM for chip %d\n", chip_id);
312 : 0 : return NULL;
313 : : }
314 : :
315 : 0 : prlog(PR_DEBUG, "IOHUB: PHB active bridge mask %x\n",
316 : : (u32) hub->fab_br0_pdt);
317 : :
318 : : /* Create PBCQs */
319 : 0 : if (proc_gen == proc_gen_p9) {
320 : 0 : io_add_phb4(hub, sp_iohubs, xscom, 0, 1, 0);
321 : 0 : io_add_phb4(hub, sp_iohubs, xscom, 1, 2, 1);
322 : 0 : io_add_phb4(hub, sp_iohubs, xscom, 2, 3, 3);
323 : : } else { /* p10 */
324 : 0 : io_add_phb4(hub, sp_iohubs, xscom, 0, 3, 0);
325 : 0 : io_add_phb4(hub, sp_iohubs, xscom, 1, 3, 3);
326 : : }
327 : :
328 : 0 : return xscom;
329 : : }
330 : :
331 : :
332 : 1 : static void io_add_p8_cec_vpd(const struct HDIF_common_hdr *sp_iohubs)
333 : : {
334 : : const struct HDIF_child_ptr *iokids;
335 : : const void *iokid;
336 : : const void *kwvpd;
337 : : unsigned int kwvpd_sz;
338 : :
339 : : /* P8 LXR0 kept in IO KID Keyword VPD */
340 : 1 : iokids = HDIF_child_arr(sp_iohubs, CECHUB_CHILD_IO_KIDS);
341 : 1 : if (!CHECK_SPPTR(iokids)) {
342 : 0 : prlog(PR_WARNING, "CEC: No IOKID child array !\n");
343 : 0 : return;
344 : : }
345 : 1 : if (!iokids->count) {
346 : 0 : prlog(PR_WARNING, "CEC: IOKID count is 0 !\n");
347 : 0 : return;
348 : : }
349 : 1 : if (be32_to_cpu(iokids->count) > 1) {
350 : 0 : prlog(PR_WARNING, "CEC: WARNING ! More than 1 IO KID !!! (%d)\n",
351 : : be32_to_cpu(iokids->count));
352 : : /* Ignoring the additional ones */
353 : : }
354 : :
355 : 1 : iokid = HDIF_child(sp_iohubs, iokids, 0, "IO KID");
356 : 1 : if (!iokid) {
357 : 0 : prlog(PR_WARNING, "CEC: No IO KID structure in child array !\n");
358 : 0 : return;
359 : : }
360 : :
361 : : /* Grab base location code for slots */
362 : 1 : io_get_loc_code(iokid, dt_root, "ibm,io-base-loc-code");
363 : :
364 : 1 : kwvpd = HDIF_get_idata(iokid, CECHUB_ASCII_KEYWORD_VPD, &kwvpd_sz);
365 : 1 : if (!kwvpd) {
366 : 0 : prlog(PR_WARNING, "CEC: No VPD entry in IO KID !\n");
367 : 0 : return;
368 : : }
369 : :
370 : : /* Grab LX load info */
371 : 1 : io_get_lx_info(kwvpd, kwvpd_sz, 0, dt_root);
372 : : }
373 : :
374 : : /*
375 : : * Assumptions:
376 : : *
377 : : * a) the IOSLOT index is the hub ID -CHECK
378 : : *
379 : : */
380 : :
381 : : static struct dt_node *dt_slots;
382 : :
383 : 0 : static void add_i2c_link(struct dt_node *node, const char *link_name,
384 : : u32 i2c_link)
385 : : {
386 : : /* FIXME: Do something not shit */
387 : 0 : dt_add_property_cells(node, link_name, i2c_link);
388 : 0 : }
389 : :
390 : : /*
391 : : * the root of the slots node has #address-cells = 2, <hub-index, phb-index>
392 : : * can we ditch hub-index?
393 : : */
394 : :
395 : :
396 : 0 : static const struct slot_map_details *find_slot_details(
397 : : const struct HDIF_common_hdr *ioslot, int entry)
398 : : {
399 : 0 : const struct slot_map_details *details = NULL;
400 : : const struct HDIF_array_hdr *arr;
401 : : unsigned int i;
402 : :
403 : 0 : arr = HDIF_get_iarray(ioslot, IOSLOT_IDATA_DETAILS, NULL);
404 : 0 : HDIF_iarray_for_each(arr, i, details)
405 : 0 : if (be16_to_cpu(details->entry) == entry)
406 : 0 : break;
407 : :
408 : 0 : return details;
409 : : }
410 : :
411 : 0 : static void parse_slot_details(struct dt_node *slot,
412 : : const struct slot_map_details *details)
413 : : {
414 : : u32 slot_caps;
415 : :
416 : : /*
417 : : * generic slot options
418 : : */
419 : :
420 : 0 : dt_add_property_cells(slot, "max-power",
421 : : be16_to_cpu(details->max_power));
422 : :
423 : 0 : if (details->perst_ctl_type == SLOT_PERST_PHB_OR_SW)
424 : 0 : dt_add_property(slot, "pci-perst", NULL, 0);
425 : 0 : else if (details->perst_ctl_type == SLOT_PERST_SW_GPIO)
426 : 0 : dt_add_property_cells(slot, "gpio-perst", details->perst_gpio);
427 : :
428 : 0 : if (details->presence_det_type == SLOT_PRESENCE_PCI)
429 : 0 : dt_add_property(slot, "pci-presence-detect", NULL, 0);
430 : :
431 : : /*
432 : : * specific slot capabilities
433 : : */
434 : 0 : slot_caps = be32_to_cpu(details->slot_caps);
435 : :
436 : 0 : if (slot_caps & SLOT_CAP_LSI)
437 : 0 : dt_add_property(slot, "lsi", NULL, 0);
438 : :
439 : 0 : if (slot_caps & SLOT_CAP_CAPI) {
440 : : /* XXX: should we be more specific here?
441 : : *
442 : : * Also we should double check that this slot
443 : : * is a root connected slot.
444 : : */
445 : 0 : dt_add_property(slot, "capi", NULL, 0);
446 : : }
447 : :
448 : 0 : if (slot_caps & SLOT_CAP_CCARD) {
449 : 0 : dt_add_property(slot, "cable-card", NULL, 0);
450 : :
451 : 0 : if (details->presence_det_type == SLOT_PRESENCE_I2C)
452 : 0 : add_i2c_link(slot, "i2c-presence-detect",
453 : 0 : be32_to_cpu(details->i2c_cable_card));
454 : : }
455 : :
456 : 0 : if (slot_caps & SLOT_CAP_HOTPLUG) {
457 : 0 : dt_add_property(slot, "hotplug", NULL, 0);
458 : :
459 : : /*
460 : : * Power control should only exist when the slot is hotplug
461 : : * capable
462 : : */
463 : 0 : if (details->power_ctrl_type == SLOT_PWR_I2C)
464 : 0 : add_i2c_link(slot, "i2c-power-ctrl",
465 : 0 : be32_to_cpu(details->i2c_power_ctl));
466 : : }
467 : :
468 : : /*
469 : : * NB: Additional NVLink specific info is added to this node
470 : : * when the SMP Link structures are parsed later on.
471 : : */
472 : 0 : if (slot_caps & SLOT_CAP_NVLINK)
473 : 0 : dt_add_property(slot, "nvlink", NULL, 0);
474 : 0 : }
475 : :
476 : 0 : struct dt_node *find_slot_entry_node(struct dt_node *root, u32 entry_id)
477 : : {
478 : : struct dt_node *node;
479 : :
480 : 0 : for (node = dt_first(root); node; node = dt_next(root, node)) {
481 : 0 : if (!dt_has_node_property(node, DT_PRIVATE "entry_id", NULL))
482 : 0 : continue;
483 : :
484 : 0 : if (dt_prop_get_u32(node, DT_PRIVATE "entry_id") == entry_id)
485 : 0 : return node;
486 : : }
487 : :
488 : 0 : return NULL;
489 : : }
490 : :
491 : : /*
492 : : * The internal HDAT representation of the various types of slot is kinda
493 : : * dumb, translate it into something more sensible
494 : : */
495 : : enum slot_types {
496 : : st_root,
497 : : st_slot,
498 : : st_rc_slot,
499 : : st_sw_upstream,
500 : : st_sw_downstream,
501 : : st_builtin
502 : : };
503 : :
504 : 0 : static const char *st_name(enum slot_types type)
505 : : {
506 : 0 : switch(type) {
507 : 0 : case st_root: return "root-complex";
508 : 0 : case st_slot: return "pluggable";
509 : 0 : case st_rc_slot: return "pluggable"; /* differentiate? */
510 : 0 : case st_sw_upstream: return "switch-up";
511 : 0 : case st_sw_downstream: return "switch-down";
512 : 0 : case st_builtin: return "builtin";
513 : : }
514 : :
515 : 0 : return "(none)";
516 : : }
517 : :
518 : 0 : static enum slot_types xlate_type(uint8_t type, u32 features)
519 : : {
520 : 0 : bool is_slot = features & SLOT_FEAT_SLOT;
521 : :
522 : 0 : switch (type) {
523 : 0 : case SLOT_TYPE_ROOT_COMPLEX:
524 : 0 : return is_slot ? st_rc_slot : st_root;
525 : 0 : case SLOT_TYPE_BUILTIN:
526 : 0 : return st_builtin;
527 : 0 : case SLOT_TYPE_SWITCH_UP:
528 : 0 : return st_sw_upstream;
529 : 0 : case SLOT_TYPE_SWITCH_DOWN:
530 : 0 : return is_slot ? st_slot : st_sw_downstream;
531 : : }
532 : :
533 : 0 : return -1; /* shouldn't happen */
534 : : }
535 : :
536 : 0 : static bool is_port(struct dt_node *n)
537 : : {
538 : : //return dt_node_is_compatible(n, "compatible", "ibm,pcie-port");
539 : 0 : return dt_node_is_compatible(n, "ibm,pcie-port");
540 : : }
541 : :
542 : : /* this only works inside parse_one_ioslot() */
543 : : #define SM_LOG(level, fmt, ...) \
544 : : prlog(level, "SLOTMAP: %x:%d:%d " \
545 : : fmt, /* user input */ \
546 : : chip_id, entry->phb_index, eid, \
547 : : ##__VA_ARGS__ /* user args */)
548 : :
549 : : #define SM_ERR(fmt, ...) SM_LOG(PR_ERR, fmt, ##__VA_ARGS__)
550 : : #define SM_DBG(fmt, ...) SM_LOG(PR_DEBUG, fmt, ##__VA_ARGS__)
551 : :
552 : 0 : static void parse_one_slot(const struct slot_map_entry *entry,
553 : : const struct slot_map_details *details, int chip_id)
554 : : {
555 : 0 : struct dt_node *node, *parent = NULL;
556 : : u16 eid, pid, vid, did;
557 : : u32 flags;
558 : : int type;
559 : :
560 : 0 : flags = be32_to_cpu(entry->features);
561 : 0 : type = xlate_type(entry->type, flags);
562 : :
563 : 0 : eid = be16_to_cpu(entry->entry_id);
564 : 0 : pid = be16_to_cpu(entry->parent_id);
565 : :
566 : 0 : SM_DBG("%s - eid = %d, pid = %d, name = %8s\n",
567 : : st_name(type), eid, pid,
568 : : strnlen(entry->name, 8) ? entry->name : "");
569 : :
570 : : /* empty slot, ignore it */
571 : 0 : if (eid == 0x0 && pid == 0x0)
572 : 0 : return;
573 : :
574 : 0 : if (type != st_root && type != st_rc_slot) {
575 : 0 : parent = find_slot_entry_node(dt_slots, pid);
576 : 0 : if (!parent) {
577 : 0 : SM_ERR("Unable to find node for parent slot (id = %d)\n",
578 : : pid);
579 : 0 : return;
580 : : }
581 : : }
582 : :
583 : 0 : switch (type) {
584 : 0 : case st_root:
585 : : case st_rc_slot:
586 : 0 : node = dt_new_2addr(dt_slots, "root-complex",
587 : 0 : chip_id, entry->phb_index);
588 : 0 : if (!node) {
589 : 0 : SM_ERR("Couldn't add DT node\n");
590 : 0 : return;
591 : : }
592 : 0 : dt_add_property_cells(node, "reg", chip_id, entry->phb_index);
593 : 0 : dt_add_property_cells(node, "#address-cells", 2);
594 : 0 : dt_add_property_cells(node, "#size-cells", 0);
595 : 0 : dt_add_property_strings(node, "compatible",
596 : : "ibm,pcie-port", "ibm,pcie-root-port");
597 : 0 : dt_add_property_cells(node, "ibm,chip-id", chip_id);
598 : 0 : parent = node;
599 : :
600 : : /*
601 : : * The representation of slots attached directly to the
602 : : * root complex is a bit wierd. If this is just a root
603 : : * complex then stop here, otherwise fall through to create
604 : : * the slot node.
605 : : */
606 : 0 : if (type == st_root)
607 : 0 : break;
608 : :
609 : : /* fallthrough*/
610 : : case st_sw_upstream:
611 : : case st_builtin:
612 : : case st_slot:
613 : 0 : if (!is_port(parent)) {
614 : 0 : SM_ERR("%s connected to %s (%d), should be %s or %s!\n",
615 : : st_name(type), parent->name, pid,
616 : : st_name(st_root), st_name(st_sw_downstream));
617 : 0 : return;
618 : : }
619 : :
620 : 0 : vid = (be32_to_cpu(entry->vendor_id) & 0xffff);
621 : 0 : did = (be32_to_cpu(entry->device_id) & 0xffff);
622 : :
623 : 0 : prlog(PR_DEBUG, "Found %s slot with %x:%x\n",
624 : : st_name(type), vid, did);
625 : :
626 : : /* The VID:DID is only meaningful for builtins and switches */
627 : 0 : if (type == st_sw_upstream && vid && did) {
628 : 0 : node = dt_new_2addr(parent, st_name(type), vid, did);
629 : 0 : dt_add_property_cells(node, "reg", vid, did);
630 : : } else {
631 : : /*
632 : : * If we get no vdid then create a "wildcard" slot
633 : : * that matches any device
634 : : */
635 : 0 : node = dt_new(parent, st_name(type));
636 : : }
637 : :
638 : 0 : if (type == st_sw_upstream) {
639 : 0 : dt_add_property_cells(node, "#address-cells", 1);
640 : 0 : dt_add_property_cells(node, "#size-cells", 0);
641 : 0 : dt_add_property_cells(node, "upstream-port",
642 : : entry->up_port);
643 : : }
644 : 0 : break;
645 : :
646 : 0 : case st_sw_downstream: /* slot connected to switch output */
647 : 0 : node = dt_new_addr(parent, "down-port", entry->down_port);
648 : 0 : dt_add_property_strings(node, "compatible",
649 : : "ibm,pcie-port");
650 : 0 : dt_add_property_cells(node, "reg", entry->down_port);
651 : :
652 : 0 : break;
653 : :
654 : 0 : default:
655 : 0 : SM_ERR("Unknown slot map type %x\n", entry->type);
656 : 0 : return;
657 : : }
658 : :
659 : : /*
660 : : * Now add any generic slot map properties.
661 : : */
662 : :
663 : : /* private since we don't want hdat stuff leaking */
664 : 0 : dt_add_property_cells(node, DT_PRIVATE "entry_id", eid);
665 : :
666 : 0 : if (entry->mrw_slot_id)
667 : 0 : dt_add_property_cells(node, "mrw-slot-id",
668 : : be16_to_cpu(entry->mrw_slot_id));
669 : :
670 : 0 : if (entry->lane_mask)
671 : 0 : dt_add_property_cells(node, "lane-mask",
672 : : be16_to_cpu(entry->lane_mask));
673 : :
674 : : /* what is the difference between this and the lane reverse? */
675 : 0 : if (entry->lane_reverse)
676 : 0 : dt_add_property_cells(node, "lanes-reversed",
677 : : be16_to_cpu(entry->lane_reverse));
678 : :
679 : 0 : if (strnlen(entry->name, sizeof(entry->name))) {
680 : : /*
681 : : * HACK: On some platforms (witherspoon) the slot label is
682 : : * applied to the device rather than the pcie downstream port
683 : : * that has the slot under it. Hack around this by moving the
684 : : * slot label up if the parent port doesn't have one.
685 : : */
686 : 0 : if (dt_node_is_compatible(node->parent, "ibm,pcie-port") &&
687 : 0 : !dt_find_property(node->parent, "ibm,slot-label")) {
688 : 0 : dt_add_property_nstr(node->parent, "ibm,slot-label",
689 : 0 : entry->name, sizeof(entry->name));
690 : : }
691 : :
692 : 0 : dt_add_property_nstr(node, "ibm,slot-label",
693 : 0 : entry->name, sizeof(entry->name));
694 : : }
695 : :
696 : 0 : if (entry->type == st_slot || entry->type == st_rc_slot)
697 : 0 : dt_add_property(node, "ibm,pluggable", NULL, 0);
698 : :
699 : 0 : if (details)
700 : 0 : parse_slot_details(node, details);
701 : : }
702 : :
703 : : /*
704 : : * Under the IOHUB structure we have and idata array describing
705 : : * the PHBs under each chip. The IOHUB structure also has a child
706 : : * array called IOSLOT which describes slot map. The i`th element
707 : : * of the IOSLOT array corresponds to the slot map of the i`th
708 : : * element of the iohubs idata array.
709 : : *
710 : : * Probably.
711 : : *
712 : : * Furthermore, arrayarrayarrayarrayarray.
713 : : */
714 : :
715 : 0 : static struct dt_node *get_slot_node(void)
716 : : {
717 : 0 : struct dt_node *slots = dt_find_by_name(dt_root, "ibm,pcie-slots");
718 : :
719 : 0 : if (!slots) {
720 : 0 : slots = dt_new(dt_root, "ibm,pcie-slots");
721 : 0 : dt_add_property_cells(slots, "#address-cells", 2);
722 : 0 : dt_add_property_cells(slots, "#size-cells", 0);
723 : : }
724 : :
725 : 0 : return slots;
726 : : }
727 : :
728 : 2 : static void io_parse_slots(const struct HDIF_common_hdr *sp_iohubs, int hub_id)
729 : : {
730 : : const struct HDIF_child_ptr *ioslot_arr;
731 : : const struct HDIF_array_hdr *entry_arr;
732 : : const struct HDIF_common_hdr *ioslot;
733 : : const struct slot_map_entry *entry;
734 : : unsigned int i, count;
735 : :
736 : 2 : if (be16_to_cpu(sp_iohubs->child_count) <= CECHUB_CHILD_IOSLOTS)
737 : 2 : return;
738 : :
739 : 0 : ioslot_arr = HDIF_child_arr(sp_iohubs, CECHUB_CHILD_IOSLOTS);
740 : 0 : if (!ioslot_arr)
741 : 0 : return;
742 : :
743 : 0 : count = be32_to_cpu(ioslot_arr->count); /* should only be 1 */
744 : 0 : if (!count)
745 : 0 : return;
746 : :
747 : 0 : dt_slots = get_slot_node();
748 : :
749 : 0 : prlog(PR_DEBUG, "CEC: Found slot map for IOHUB %d\n", hub_id);
750 : 0 : if (count > 1)
751 : 0 : prerror("CEC: Multiple IOSLOTs found for IO HUB %d\n", hub_id);
752 : :
753 : 0 : ioslot = HDIF_child(sp_iohubs, ioslot_arr, 0, "IOSLOT");
754 : 0 : if (!ioslot)
755 : 0 : return;
756 : :
757 : 0 : entry_arr = HDIF_get_iarray(ioslot, IOSLOT_IDATA_SLOTMAP, NULL);
758 : 0 : HDIF_iarray_for_each(entry_arr, i, entry) {
759 : : const struct slot_map_details *details;
760 : :
761 : 0 : details = find_slot_details(ioslot,
762 : 0 : be16_to_cpu(entry->entry_id));
763 : 0 : parse_one_slot(entry, details, hub_id);
764 : : }
765 : : }
766 : :
767 : 1 : static void io_parse_fru(const void *sp_iohubs)
768 : : {
769 : : unsigned int i;
770 : : int count;
771 : :
772 : 1 : count = HDIF_get_iarray_size(sp_iohubs, CECHUB_FRU_IO_HUBS);
773 : 1 : if (count < 1) {
774 : 0 : prerror("CEC: IO FRU with no chips !\n");
775 : 0 : return;
776 : : }
777 : :
778 : 1 : prlog(PR_INFO, "CEC: %d chips in FRU\n", count);
779 : :
780 : : /* Iterate IO hub array */
781 : 3 : for (i = 0; i < count; i++) {
782 : : const struct cechub_io_hub *hub;
783 : : unsigned int size, hub_id;
784 : : uint32_t chip_id;
785 : :
786 : 2 : hub = HDIF_get_iarray_item(sp_iohubs, CECHUB_FRU_IO_HUBS,
787 : : i, &size);
788 : 2 : if (!hub || size < CECHUB_IOHUB_MIN_SIZE) {
789 : 0 : prerror("CEC: IO-HUB Chip %d bad idata\n", i);
790 : 0 : continue;
791 : : }
792 : :
793 : 2 : switch (hub->flags & CECHUB_HUB_FLAG_STATE_MASK) {
794 : 2 : case CECHUB_HUB_FLAG_STATE_OK:
795 : 2 : prlog(PR_DEBUG, "CEC: IO Hub Chip #%d OK\n", i);
796 : 2 : break;
797 : 0 : case CECHUB_HUB_FLAG_STATE_FAILURES:
798 : 0 : prlog(PR_WARNING, "CEC: IO Hub Chip #%d OK"
799 : : " with failures\n", i);
800 : 0 : break;
801 : 0 : case CECHUB_HUB_FLAG_STATE_NOT_INST:
802 : 0 : prlog(PR_DEBUG, "CEC: IO Hub Chip #%d"
803 : : " Not installed\n", i);
804 : 0 : continue;
805 : 0 : case CECHUB_HUB_FLAG_STATE_UNUSABLE:
806 : 0 : prlog(PR_DEBUG, "CEC: IO Hub Chip #%d Unusable\n", i);
807 : 0 : continue;
808 : : }
809 : :
810 : 2 : hub_id = be16_to_cpu(hub->iohub_id);
811 : :
812 : : /* GX BAR assignment */
813 : 2 : prlog(PR_DEBUG, "CEC: PChip: %d HUB ID: %04x [EC=0x%x]"
814 : : " Hub#=%d)\n",
815 : : be32_to_cpu(hub->proc_chip_id), hub_id,
816 : : be32_to_cpu(hub->ec_level), be16_to_cpu(hub->hub_num));
817 : :
818 : 2 : switch(hub_id) {
819 : 2 : case CECHUB_HUB_MURANO:
820 : : case CECHUB_HUB_MURANO_SEGU:
821 : 2 : prlog(PR_INFO, "CEC: Murano !\n");
822 : 2 : io_add_p8(hub, sp_iohubs);
823 : 2 : break;
824 : 0 : case CECHUB_HUB_VENICE_WYATT:
825 : 0 : prlog(PR_INFO, "CEC: Venice !\n");
826 : 0 : io_add_p8(hub, sp_iohubs);
827 : 0 : break;
828 : 0 : case CECHUB_HUB_NIMBUS_SFORAZ:
829 : : case CECHUB_HUB_NIMBUS_MONZA:
830 : : case CECHUB_HUB_NIMBUS_LAGRANGE:
831 : 0 : prlog(PR_INFO, "CEC: Nimbus !\n");
832 : 0 : io_add_p9(hub, sp_iohubs);
833 : 0 : break;
834 : 0 : case CECHUB_HUB_CUMULUS_DUOMO:
835 : 0 : prlog(PR_INFO, "CEC: Cumulus !\n");
836 : 0 : io_add_p9(hub, sp_iohubs);
837 : 0 : break;
838 : 0 : case CECHUB_HUB_AXONE_HOPPER:
839 : 0 : prlog(PR_INFO, "CEC: Axone !\n");
840 : 0 : io_add_p9(hub, sp_iohubs);
841 : 0 : break;
842 : 0 : case CECHUB_HUB_RAINIER:
843 : 0 : prlog(PR_INFO, "CEC: Rainier !\n");
844 : 0 : io_add_p9(hub, sp_iohubs);
845 : 0 : break;
846 : 0 : case CECHUB_HUB_DENALI:
847 : 0 : prlog(PR_INFO, "CEC: Denali !\n");
848 : 0 : io_add_p9(hub, sp_iohubs);
849 : 0 : break;
850 : 0 : default:
851 : 0 : prlog(PR_ERR, "CEC: Hub ID 0x%04x unsupported !\n",
852 : : hub_id);
853 : : }
854 : :
855 : 2 : chip_id = pcid_to_chip_id(be32_to_cpu(hub->proc_chip_id));
856 : :
857 : : /* parse the slot map if we have one */
858 : 2 : io_parse_slots(sp_iohubs, chip_id);
859 : : }
860 : :
861 : 1 : if (proc_gen == proc_gen_p8 || proc_gen == proc_gen_p9 || proc_gen == proc_gen_p10)
862 : 1 : io_add_p8_cec_vpd(sp_iohubs);
863 : : }
864 : :
865 : 1 : void io_parse(void)
866 : : {
867 : : const struct HDIF_common_hdr *sp_iohubs;
868 : : unsigned int i, size;
869 : :
870 : : /* Look for IO Hubs */
871 : 1 : if (!get_hdif(&spiras->ntuples.cec_iohub_fru, "IO HUB")) {
872 : 0 : prerror("CEC: Cannot locate IO Hub FRU data !\n");
873 : 0 : return;
874 : : }
875 : :
876 : : /*
877 : : * Note about LXRn numbering ...
878 : : *
879 : : * I can't completely make sense of what that is supposed to be, so
880 : : * for now, what we do is look for the first one we can find and
881 : : * increment it for each chip. Works for the machines I have here
882 : : */
883 : :
884 : 2 : for_each_ntuple_idx(&spiras->ntuples.cec_iohub_fru, sp_iohubs, i,
885 : : CECHUB_FRU_HDIF_SIG) {
886 : : const struct cechub_hub_fru_id *fru_id_data;
887 : : unsigned int type;
888 : : static const char *typestr[] = {
889 : : "Reservation",
890 : : "Card",
891 : : "CPU Card",
892 : : "Backplane",
893 : : "Backplane Extension"
894 : : };
895 : 1 : fru_id_data = HDIF_get_idata(sp_iohubs, CECHUB_FRU_ID_DATA_AREA,
896 : : &size);
897 : 1 : if (!fru_id_data || size < sizeof(struct cechub_hub_fru_id)) {
898 : 0 : prerror("CEC: IO-HUB FRU %d, bad ID data\n", i);
899 : 0 : continue;
900 : : }
901 : 1 : type = be32_to_cpu(fru_id_data->card_type);
902 : :
903 : 1 : prlog(PR_INFO, "CEC: HUB FRU %d is %s\n",
904 : : i, type > 4 ? "Unknown" : typestr[type]);
905 : :
906 : : /*
907 : : * We currently only handle the backplane (Juno) and
908 : : * processor FRU (P8 machines)
909 : : */
910 : 1 : if (type != CECHUB_FRU_TYPE_CEC_BKPLANE &&
911 : : type != CECHUB_FRU_TYPE_CPU_CARD) {
912 : 0 : prerror("CEC: Unsupported type\n");
913 : 0 : continue;
914 : : }
915 : :
916 : : /* We don't support Hubs connected to pass-through ports */
917 : 1 : if (fru_id_data->flags & (CECHUB_FRU_FLAG_HEADLESS |
918 : : CECHUB_FRU_FLAG_PASSTHROUGH)) {
919 : 0 : prerror("CEC: Headless or Passthrough unsupported\n");
920 : 0 : continue;
921 : : }
922 : :
923 : : /* Ok, we have a reasonable candidate */
924 : 1 : io_parse_fru(sp_iohubs);
925 : : }
926 : : }
927 : :
|