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 <cpu.h>
5 : : #include <device.h>
6 : : #include <vpd.h>
7 : : #include <ccan/str/str.h>
8 : : #include <libfdt/libfdt.h>
9 : : #include <mem_region.h>
10 : : #include <types.h>
11 : : #include <inttypes.h>
12 : : #include <processor.h>
13 : :
14 : : #include "spira.h"
15 : : #include "hdata.h"
16 : :
17 : : struct HDIF_ram_area_id {
18 : : __be16 id;
19 : : #define RAM_AREA_INSTALLED 0x8000
20 : : #define RAM_AREA_FUNCTIONAL 0x4000
21 : : __be16 flags;
22 : : __be32 dimm_id;
23 : : __be32 speed;
24 : : } __packed;
25 : :
26 : : struct HDIF_ram_area_size {
27 : : __be32 reserved1;
28 : : __be32 mb;
29 : : } __packed;
30 : :
31 : : struct HDIF_ms_area_address_range {
32 : : __be64 start;
33 : : __be64 end;
34 : : __be32 chip;
35 : : __be32 mirror_attr;
36 : : __be64 mirror_start;
37 : : __be32 controller_id;
38 : : __be32 phys_attr;
39 : : } __packed;
40 : : #define PHYS_ATTR_TYPE_MASK 0xff000000
41 : : #define PHYS_ATTR_TYPE_STD 0
42 : : #define PHYS_ATTR_TYPE_NVDIMM 1
43 : : #define PHYS_ATTR_TYPE_MRAM 2
44 : : #define PHYS_ATTR_TYPE_PCM 3
45 : :
46 : : #define PHYS_ATTR_STATUS_MASK 0x00ff0000
47 : : /*
48 : : * The values here are mutually exclusive. I have no idea why anyone
49 : : * decided encoding these are flags rather than sequential numbers was
50 : : * a good idea, but here we are.
51 : : */
52 : : #define PHYS_ATTR_STATUS_CANT_SAVE 0x01
53 : : #define PHYS_ATTR_STATUS_SAVE_FAILED 0x02
54 : : #define PHYS_ATTR_STATUS_SAVED 0x04
55 : : #define PHYS_ATTR_STATUS_NOT_SAVED 0x08
56 : : #define PHYS_ATTR_STATUS_ENCRYPTED 0x10
57 : : #define PHYS_ATTR_STATUS_ERR_DETECTED 0x40
58 : : #define PHYS_ATTR_STATUS_MEM_INVALID 0xff
59 : :
60 : : /* Memory Controller ID for Nimbus P9 systems */
61 : : #define MS_CONTROLLER_MCBIST_ID(id) GETFIELD(PPC_BITMASK32(0, 1), id)
62 : : #define MS_CONTROLLER_MCS_ID(id) GETFIELD(PPC_BITMASK32(4, 7), id)
63 : : #define MS_CONTROLLER_MCA_ID(id) GETFIELD(PPC_BITMASK32(8, 15), id)
64 : :
65 : : /* Memory Controller ID for P9 AXONE systems */
66 : : #define MS_CONTROLLER_MC_ID(id) GETFIELD(PPC_BITMASK32(0, 1), id)
67 : : #define MS_CONTROLLER_MI_ID(id) GETFIELD(PPC_BITMASK32(4, 7), id)
68 : : #define MS_CONTROLLER_MCC_ID(id) GETFIELD(PPC_BITMASK32(8, 15), id)
69 : : #define MS_CONTROLLER_OMI_ID(id) GETFIELD(PPC_BITMASK32(16, 31), id)
70 : :
71 : : struct HDIF_ms_area_id {
72 : : __be16 id;
73 : : #define MS_PTYPE_RISER_CARD 0x8000
74 : : #define MS_PTYPE_MEM_CARD 0x4000
75 : : #define MS_PTYPE_CEC_FRU 0x2000
76 : : #define MS_PTYPE_HYBRID_CARD 0x1000
77 : : __be16 parent_type;
78 : : #define MS_AREA_INSTALLED 0x8000
79 : : #define MS_AREA_FUNCTIONAL 0x4000
80 : : #define MS_AREA_SHARED 0x2000
81 : : __be16 flags;
82 : : __be16 share_id;
83 : : } __packed;
84 : :
85 : :
86 : : // FIXME: it should be 9, current HDATs are broken
87 : : #define MSAREA_IDATA_MMIO_IDX 8
88 : : struct HDIF_ms_area_ocmb_mmio {
89 : : __be64 range_start;
90 : : __be64 range_end;
91 : : __be32 controller_id;
92 : : __be32 proc_chip_id;
93 : : __be64 hbrt_id;
94 : : #define OCMB_SCOM_8BYTE_ACCESS PPC_BIT(0)
95 : : #define OCMB_SCOM_4BYTE_ACCESS PPC_BIT(1)
96 : : __be64 flags;
97 : : } __packed;
98 : :
99 : 1 : static void append_chip_id(struct dt_node *mem, u32 id)
100 : : {
101 : : struct dt_property *prop;
102 : : size_t len, i;
103 : :
104 : 1 : prop = __dt_find_property(mem, "ibm,chip-id");
105 : 1 : if (!prop)
106 : 1 : return;
107 : 1 : len = prop->len >> 2;
108 : :
109 : : /* Check if it exists already */
110 : 1 : for (i = 0; i < len; i++) {
111 : 1 : if (dt_property_get_cell(prop, i) == id)
112 : 1 : return;
113 : : }
114 : :
115 : : /* Add it to the list */
116 : 0 : dt_resize_property(&prop, (len + 1) << 2);
117 : 0 : dt_property_set_cell(prop, len, id);
118 : : }
119 : :
120 : 0 : static void update_status(struct dt_node *mem, uint32_t status)
121 : : {
122 : 0 : switch (status) {
123 : 0 : case PHYS_ATTR_STATUS_CANT_SAVE:
124 : 0 : if (!dt_find_property(mem, "save-trigged-unarmed"))
125 : 0 : dt_add_property(mem, "save-trigger-unarmed", NULL, 0);
126 : 0 : break;
127 : :
128 : 0 : case PHYS_ATTR_STATUS_SAVE_FAILED:
129 : 0 : if (!dt_find_property(mem, "save-failed"))
130 : 0 : dt_add_property(mem, "save-failed", NULL, 0);
131 : :
132 : 0 : break;
133 : :
134 : 0 : case PHYS_ATTR_STATUS_MEM_INVALID:
135 : 0 : if (dt_find_property(mem, "save-trigged-unarmed"))
136 : 0 : dt_add_property_string(mem, "status",
137 : : "disabled-memory-invalid");
138 : 0 : break;
139 : : }
140 : 0 : }
141 : :
142 : 2 : static bool add_address_range(struct dt_node *root,
143 : : const struct HDIF_ms_area_id *id,
144 : : const struct HDIF_ms_area_address_range *arange,
145 : : uint32_t mem_type, uint32_t mem_status)
146 : : {
147 : 2 : const char *compat = NULL, *dev_type = NULL, *name = NULL;
148 : : struct dt_node *mem;
149 : : u32 chip_id;
150 : : u64 reg[2];
151 : :
152 : 2 : chip_id = pcid_to_chip_id(be32_to_cpu(arange->chip));
153 : :
154 : 2 : prlog(PR_DEBUG, " Range: 0x%016llx..0x%016llx "
155 : : "on Chip 0x%x mattr: 0x%x pattr: 0x%x status:0x%x\n",
156 : : (long long)be64_to_cpu(arange->start),
157 : : (long long)be64_to_cpu(arange->end),
158 : : chip_id, be32_to_cpu(arange->mirror_attr),
159 : : mem_type, mem_status);
160 : :
161 : : /* reg contains start and length */
162 : 2 : reg[0] = cleanup_addr(be64_to_cpu(arange->start));
163 : 2 : reg[1] = cleanup_addr(be64_to_cpu(arange->end)) - reg[0];
164 : :
165 : 2 : switch (mem_type) {
166 : 2 : case PHYS_ATTR_TYPE_STD:
167 : 2 : name = "memory";
168 : 2 : dev_type = "memory";
169 : 2 : break;
170 : :
171 : 0 : case PHYS_ATTR_TYPE_NVDIMM:
172 : : case PHYS_ATTR_TYPE_MRAM:
173 : : case PHYS_ATTR_TYPE_PCM:
174 : : /* fall through */
175 : 0 : name = "nvdimm";
176 : 0 : compat = "pmem-region";
177 : 0 : break;
178 : :
179 : : /*
180 : : * Future memory types could be volatile or non-volatile. Bail if don't
181 : : * recognise the type so we don't end up trashing data accidently.
182 : : */
183 : 0 : default:
184 : 0 : return false;
185 : : }
186 : :
187 : 2 : if (be16_to_cpu(id->flags) & MS_AREA_SHARED) {
188 : 2 : mem = dt_find_by_name_addr(dt_root, name, reg[0]);
189 : 2 : if (mem) {
190 : 1 : append_chip_id(mem, chip_id);
191 : 1 : if (mem_type == PHYS_ATTR_TYPE_NVDIMM)
192 : 0 : update_status(mem, mem_status);
193 : 1 : return true;
194 : : }
195 : : }
196 : :
197 : 1 : mem = dt_new_addr(root, name, reg[0]);
198 : 1 : if (compat)
199 : 0 : dt_add_property_string(mem, "compatible", compat);
200 : 1 : if (dev_type)
201 : 1 : dt_add_property_string(mem, "device_type", dev_type);
202 : :
203 : : /* add in the nvdimm backup status flags */
204 : 1 : if (mem_type == PHYS_ATTR_TYPE_NVDIMM)
205 : 0 : update_status(mem, mem_status);
206 : :
207 : : /* common properties */
208 : :
209 : 1 : dt_add_property_u64s(mem, "reg", reg[0], reg[1]);
210 : 1 : dt_add_property_cells(mem, "ibm,chip-id", chip_id);
211 : 1 : return true;
212 : : }
213 : :
214 : 2 : static u32 add_chip_id_to_ram_area(const struct HDIF_common_hdr *msarea,
215 : : struct dt_node *ram_area)
216 : : {
217 : : const struct HDIF_array_hdr *arr;
218 : : const struct HDIF_ms_area_address_range *arange;
219 : : unsigned int size;
220 : : u32 chip_id;
221 : :
222 : : /* Safe to assume pointers are valid here. */
223 : 2 : arr = HDIF_get_idata(msarea, 4, &size);
224 : 2 : arange = (void *)arr + be32_to_cpu(arr->offset);
225 : 2 : chip_id = pcid_to_chip_id(be32_to_cpu(arange->chip));
226 : 2 : dt_add_property_cells(ram_area, "ibm,chip-id", chip_id);
227 : :
228 : 2 : return chip_id;
229 : : }
230 : :
231 : 2 : static void add_bus_freq_to_ram_area(struct dt_node *ram_node, u32 chip_id)
232 : : {
233 : : const struct sppcia_cpu_timebase *timebase;
234 : 2 : bool got_pcia = false;
235 : : const void *pcia;
236 : : u64 freq;
237 : : u32 size;
238 : :
239 : 2 : pcia = get_hdif(&spiras->ntuples.pcia, SPPCIA_HDIF_SIG);
240 : 2 : if (!pcia) {
241 : 0 : prlog(PR_WARNING, "HDAT: Failed to add memory bus frequency "
242 : : "as PCIA does not exist\n");
243 : 0 : return;
244 : : }
245 : :
246 : 2 : for_each_pcia(spiras, pcia) {
247 : : const struct sppcia_core_unique *id;
248 : :
249 : 2 : id = HDIF_get_idata(pcia, SPPCIA_IDATA_CORE_UNIQUE, &size);
250 : 2 : if (!id || size < sizeof(*id)) {
251 : 0 : prlog(PR_WARNING, "HDAT: Bad id size %u @ %p\n", size, id);
252 : 0 : return;
253 : : }
254 : :
255 : 2 : if (chip_id == pcid_to_chip_id(be32_to_cpu(id->proc_chip_id))) {
256 : 2 : got_pcia = true;
257 : 2 : break;
258 : : }
259 : : }
260 : :
261 : 2 : if (got_pcia == false)
262 : 0 : return;
263 : :
264 : 2 : timebase = HDIF_get_idata(pcia, SPPCIA_IDATA_TIMEBASE, &size);
265 : 2 : if (!timebase || size < sizeof(*timebase)) {
266 : : /**
267 : : * @fwts-label HDATBadTimebaseSize
268 : : * @fwts-advice HDAT described an invalid size for timebase,
269 : : * which means there's a disagreement between HDAT and OPAL.
270 : : * This is most certainly a firmware bug.
271 : : */
272 : 0 : prlog(PR_ERR, "HDAT: Bad timebase size %u @ %p\n", size,
273 : : timebase);
274 : 0 : return;
275 : : }
276 : :
277 : 2 : freq = ((u64)be32_to_cpu(timebase->memory_bus_frequency)) * 1000000ul;
278 : 2 : dt_add_property_u64(ram_node, "ibm,memory-bus-frequency", freq);
279 : : }
280 : :
281 : 2 : static void add_size_to_ram_area(struct dt_node *ram_node,
282 : : const struct HDIF_common_hdr *ramarea)
283 : : {
284 : : char str[16];
285 : : const struct HDIF_ram_area_size *ram_area_sz;
286 : :
287 : : /* DIMM size */
288 : 2 : ram_area_sz = HDIF_get_idata(ramarea, 3, NULL);
289 : 2 : if (!CHECK_SPPTR(ram_area_sz))
290 : 0 : return;
291 : :
292 : 2 : memset(str, 0, 16);
293 : 2 : snprintf(str, 16, "%d", be32_to_cpu(ram_area_sz->mb));
294 : 2 : dt_add_property_string(ram_node, "size", str);
295 : : }
296 : :
297 : 2 : static void vpd_add_ram_area(const struct HDIF_common_hdr *msarea)
298 : : {
299 : : unsigned int i;
300 : : unsigned int ram_sz;
301 : : const struct HDIF_common_hdr *ramarea;
302 : : const struct HDIF_child_ptr *ramptr;
303 : : const struct HDIF_ram_area_id *ram_id;
304 : : struct dt_node *ram_node;
305 : : u32 chip_id;
306 : : const void *vpd_blob;
307 : :
308 : 2 : ramptr = HDIF_child_arr(msarea, 0);
309 : 2 : if (!CHECK_SPPTR(ramptr)) {
310 : 0 : prerror("MS AREA: No RAM area at %p\n", msarea);
311 : 0 : return;
312 : : }
313 : :
314 : 4 : for (i = 0; i < be32_to_cpu(ramptr->count); i++) {
315 : 2 : ramarea = HDIF_child(msarea, ramptr, i, "RAM ");
316 : 2 : if (!CHECK_SPPTR(ramarea))
317 : 0 : continue;
318 : :
319 : 2 : ram_id = HDIF_get_idata(ramarea, 2, &ram_sz);
320 : 2 : if (!CHECK_SPPTR(ram_id))
321 : 0 : continue;
322 : :
323 : : /* Don't add VPD for non-existent RAM */
324 : 2 : if (!(be16_to_cpu(ram_id->flags) & RAM_AREA_INSTALLED))
325 : 0 : continue;
326 : :
327 : 2 : ram_node = dt_add_vpd_node(ramarea, 0, 1);
328 : 2 : if (!ram_node)
329 : 0 : continue;
330 : :
331 : 2 : chip_id = add_chip_id_to_ram_area(msarea, ram_node);
332 : 2 : add_bus_freq_to_ram_area(ram_node, chip_id);
333 : :
334 : 2 : if (ram_sz >= offsetof(struct HDIF_ram_area_id, speed)) {
335 : 0 : dt_add_property_cells(ram_node, "frequency",
336 : : be32_to_cpu(ram_id->speed)*1000000);
337 : : }
338 : :
339 : 2 : vpd_blob = HDIF_get_idata(ramarea, 1, &ram_sz);
340 : :
341 : : /* DIMM size */
342 : 2 : add_size_to_ram_area(ram_node, ramarea);
343 : : /*
344 : : * For direct-attached memory we have a DDR "Serial
345 : : * Presence Detection" blob rather than an IBM keyword
346 : : * blob.
347 : : */
348 : 2 : if (!vpd_valid(vpd_blob, ram_sz))
349 : 0 : dt_add_property(ram_node, "spd", vpd_blob, ram_sz);
350 : : }
351 : : }
352 : :
353 : 0 : static void vpd_parse_spd(struct dt_node *dimm, const char *spd, u32 size)
354 : : {
355 : : __be16 *vendor;
356 : : __be32 *sn;
357 : :
358 : : /* SPD is too small */
359 : 0 : if (size < 512) {
360 : 0 : prlog(PR_WARNING, "MSVPD: Invalid SPD size. "
361 : : "Expected 512 bytes, got %d\n", size);
362 : 0 : return;
363 : : }
364 : :
365 : : /* Supports DDR4 format pasing only */
366 : 0 : if (spd[0x2] < 0xc) {
367 : 0 : prlog(PR_WARNING,
368 : : "MSVPD: SPD format (%x) not supported\n", spd[0x2]);
369 : 0 : return;
370 : : }
371 : :
372 : 0 : dt_add_property_string(dimm, "device_type", "memory-dimm-ddr4");
373 : :
374 : : /* DRAM device type */
375 : 0 : dt_add_property_cells(dimm, "memory-id", spd[0x2]);
376 : :
377 : : /* Module revision code */
378 : 0 : dt_add_property_cells(dimm, "product-version", spd[0x15d]);
379 : :
380 : : /* Serial number */
381 : 0 : sn = (__be32 *)&spd[0x145];
382 : 0 : dt_add_property_cells(dimm, "serial-number", be32_to_cpu(*sn));
383 : :
384 : : /* Part number */
385 : 0 : dt_add_property_nstr(dimm, "part-number", &spd[0x149], 20);
386 : :
387 : : /* Module manufacturer ID */
388 : 0 : vendor = (__be16 *)&spd[0x140];
389 : 0 : dt_add_property_cells(dimm, "manufacturer-id", be16_to_cpu(*vendor));
390 : : }
391 : :
392 : 0 : static void add_dimm_info(struct dt_node *parent,
393 : : const struct HDIF_common_hdr *msarea)
394 : : {
395 : : unsigned int i, size;
396 : : const struct HDIF_child_ptr *ramptr;
397 : : const struct HDIF_common_hdr *ramarea;
398 : : const struct spira_fru_id *fru_id;
399 : : const struct HDIF_ram_area_id *ram_id;
400 : : const struct HDIF_ram_area_size *ram_area_sz;
401 : : struct dt_node *dimm;
402 : : const void *vpd_blob;
403 : :
404 : 0 : ramptr = HDIF_child_arr(msarea, 0);
405 : 0 : if (!CHECK_SPPTR(ramptr)) {
406 : 0 : prerror("MS AREA: No RAM area at %p\n", msarea);
407 : 0 : return;
408 : : }
409 : :
410 : 0 : for (i = 0; i < be32_to_cpu(ramptr->count); i++) {
411 : 0 : ramarea = HDIF_child(msarea, ramptr, i, "RAM ");
412 : 0 : if (!CHECK_SPPTR(ramarea))
413 : 0 : continue;
414 : :
415 : 0 : fru_id = HDIF_get_idata(ramarea, 0, NULL);
416 : 0 : if (!fru_id)
417 : 0 : continue;
418 : :
419 : : /* Use Resource ID to add dimm node */
420 : 0 : dimm = dt_find_by_name_addr(parent, "dimm",
421 : 0 : be16_to_cpu(fru_id->rsrc_id));
422 : 0 : if (dimm)
423 : 0 : continue;
424 : 0 : dimm= dt_new_addr(parent, "dimm", be16_to_cpu(fru_id->rsrc_id));
425 : 0 : assert(dimm);
426 : 0 : dt_add_property_cells(dimm, "reg", be16_to_cpu(fru_id->rsrc_id));
427 : :
428 : : /* Add location code */
429 : 0 : slca_vpd_add_loc_code(dimm, be16_to_cpu(fru_id->slca_index));
430 : :
431 : : /* DIMM size */
432 : 0 : ram_area_sz = HDIF_get_idata(ramarea, 3, NULL);
433 : 0 : if (!CHECK_SPPTR(ram_area_sz))
434 : 0 : continue;
435 : 0 : dt_add_property_cells(dimm, "size", be32_to_cpu(ram_area_sz->mb));
436 : :
437 : : /* DIMM state */
438 : 0 : ram_id = HDIF_get_idata(ramarea, 2, NULL);
439 : 0 : if (!CHECK_SPPTR(ram_id))
440 : 0 : continue;
441 : :
442 : 0 : if ((be16_to_cpu(ram_id->flags) & RAM_AREA_INSTALLED) &&
443 : 0 : (be16_to_cpu(ram_id->flags) & RAM_AREA_FUNCTIONAL))
444 : 0 : dt_add_property_string(dimm, "status", "okay");
445 : : else
446 : 0 : dt_add_property_string(dimm, "status", "disabled");
447 : :
448 : 0 : vpd_blob = HDIF_get_idata(ramarea, 1, &size);
449 : 0 : if (!CHECK_SPPTR(vpd_blob))
450 : 0 : continue;
451 : 0 : if (vpd_valid(vpd_blob, size))
452 : 0 : vpd_data_parse(dimm, vpd_blob, size);
453 : : else
454 : 0 : vpd_parse_spd(dimm, vpd_blob, size);
455 : : }
456 : : }
457 : :
458 : 0 : static inline void dt_add_mem_reg_property(struct dt_node *node, u64 addr)
459 : : {
460 : 0 : dt_add_property_cells(node, "#address-cells", 1);
461 : 0 : dt_add_property_cells(node, "#size-cells", 0);
462 : 0 : dt_add_property_cells(node, "reg", addr);
463 : 0 : }
464 : :
465 : 0 : static void add_memory_controller_p9n(const struct HDIF_common_hdr *msarea,
466 : : const struct HDIF_ms_area_address_range *arange)
467 : : {
468 : : uint32_t chip_id;
469 : : uint32_t controller_id, mcbist_id, mcs_id, mca_id;
470 : : struct dt_node *xscom, *mcbist, *mcs, *mca;
471 : :
472 : 0 : chip_id = pcid_to_chip_id(be32_to_cpu(arange->chip));
473 : 0 : controller_id = be32_to_cpu(arange->controller_id);
474 : 0 : xscom = find_xscom_for_chip(chip_id);
475 : 0 : if (!xscom) {
476 : 0 : prlog(PR_WARNING,
477 : : "MS AREA: Can't find XSCOM for chip %d\n", chip_id);
478 : 0 : return;
479 : : }
480 : :
481 : 0 : mcbist_id = MS_CONTROLLER_MCBIST_ID(controller_id);
482 : 0 : mcbist = dt_find_by_name_addr(xscom, "mcbist", mcbist_id);
483 : 0 : if (!mcbist) {
484 : 0 : mcbist = dt_new_addr(xscom, "mcbist", mcbist_id);
485 : 0 : assert(mcbist);
486 : 0 : dt_add_property_cells(mcbist, "#address-cells", 1);
487 : 0 : dt_add_property_cells(mcbist, "#size-cells", 0);
488 : 0 : dt_add_property_cells(mcbist, "reg", mcbist_id, 0);
489 : : }
490 : :
491 : 0 : mcs_id = MS_CONTROLLER_MCS_ID(controller_id);
492 : 0 : mcs = dt_find_by_name_addr(mcbist, "mcs", mcs_id);
493 : 0 : if (!mcs) {
494 : 0 : mcs = dt_new_addr(mcbist, "mcs", mcs_id);
495 : 0 : assert(mcs);
496 : 0 : dt_add_mem_reg_property(mcs, mcs_id);
497 : : }
498 : :
499 : 0 : mca_id = MS_CONTROLLER_MCA_ID(controller_id);
500 : 0 : mca = dt_find_by_name_addr(mcs, "mca", mca_id);
501 : 0 : if (!mca) {
502 : 0 : mca = dt_new_addr(mcs, "mca", mca_id);
503 : 0 : assert(mca);
504 : 0 : dt_add_mem_reg_property(mca, mca_id);
505 : : }
506 : :
507 : 0 : add_dimm_info(mca, msarea);
508 : : }
509 : :
510 : 2 : static void add_memory_buffer_mmio(const struct HDIF_common_hdr *msarea)
511 : : {
512 : : const struct HDIF_ms_area_ocmb_mmio *mmio;
513 : 2 : uint64_t min_addr = ~0ull, hbrt_id = 0;
514 : : const struct HDIF_array_hdr *array;
515 : 2 : unsigned int i, count, ranges = 0;
516 : : struct dt_node *membuf;
517 : : beint64_t *reg, *flags;
518 : :
519 : 2 : if (proc_gen <= proc_gen_p9 && PVR_TYPE(mfspr(SPR_PVR)) != PVR_TYPE_P9P)
520 : 2 : return;
521 : :
522 : 0 : if (be16_to_cpu(msarea->version) < 0x50) {
523 : 0 : prlog(PR_WARNING, "MS AREA: Inconsistent MSAREA version %x for P9P system",
524 : : be16_to_cpu(msarea->version));
525 : 0 : return;
526 : : }
527 : :
528 : 0 : array = HDIF_get_iarray(msarea, MSAREA_IDATA_MMIO_IDX, &count);
529 : 0 : if (!array || count <= 0) {
530 : 0 : prerror("MS AREA: No OCMB MMIO array at MS Area %p\n", msarea);
531 : 0 : return;
532 : : }
533 : :
534 : 0 : reg = zalloc(count * 2 * sizeof(*reg));
535 : 0 : flags = zalloc(count * sizeof(*flags));
536 : :
537 : : /* grab the hbrt id from the first range. */
538 : 0 : HDIF_iarray_for_each(array, i, mmio) {
539 : 0 : hbrt_id = be64_to_cpu(mmio->hbrt_id);
540 : 0 : break;
541 : : }
542 : :
543 : 0 : prlog(PR_DEBUG, "Adding memory buffer MMIO ranges for %"PRIx64"\n",
544 : : hbrt_id);
545 : :
546 : 0 : HDIF_iarray_for_each(array, i, mmio) {
547 : : uint64_t start, end;
548 : :
549 : 0 : if (hbrt_id != be64_to_cpu(mmio->hbrt_id)) {
550 : 0 : prerror("HBRT ID mismatch!\n");
551 : 0 : continue;
552 : : }
553 : :
554 : 0 : start = cleanup_addr(be64_to_cpu(mmio->range_start));
555 : 0 : end = cleanup_addr(be64_to_cpu(mmio->range_end));
556 : 0 : if (start < min_addr)
557 : 0 : min_addr = start;
558 : :
559 : 0 : prlog(PR_DEBUG, " %"PRIx64" - [%016"PRIx64"-%016"PRIx64")\n",
560 : : hbrt_id, start, end);
561 : :
562 : 0 : reg[2 * ranges ] = cpu_to_be64(start);
563 : 0 : reg[2 * ranges + 1] = cpu_to_be64(end - start + 1);
564 : 0 : flags[ranges] = mmio->flags; /* both are BE */
565 : 0 : ranges++;
566 : : }
567 : :
568 : 0 : membuf = dt_find_by_name_addr(dt_root, "memory-buffer", min_addr);
569 : 0 : if (membuf) {
570 : 0 : prerror("attempted to duplicate %s\n", membuf->name);
571 : 0 : goto out;
572 : : }
573 : :
574 : 0 : membuf = dt_new_addr(dt_root, "memory-buffer", min_addr);
575 : 0 : assert(membuf);
576 : :
577 : 0 : dt_add_property_string(membuf, "compatible", "ibm,explorer");
578 : 0 : dt_add_property_cells(membuf, "ibm,chip-id", hbrt_id);
579 : :
580 : : /*
581 : : * FIXME: We should probably be sorting the address ranges based
582 : : * on the starting address.
583 : : */
584 : 0 : dt_add_property(membuf, "reg", reg, sizeof(*reg) * 2 * ranges);
585 : 0 : dt_add_property(membuf, "flags", flags, sizeof(*flags) * ranges);
586 : :
587 : 0 : out:
588 : 0 : free(flags);
589 : 0 : free(reg);
590 : : }
591 : :
592 : 2 : static void add_memory_controller(const struct HDIF_common_hdr *msarea,
593 : : const struct HDIF_ms_area_address_range *arange)
594 : : {
595 : 2 : const uint32_t version = PVR_TYPE(mfspr(SPR_PVR));
596 : : /*
597 : : * Memory hierarchy may change between processor version. Presently
598 : : * it's only creating memory hierarchy for P9 (Nimbus) and P9P (Axone).
599 : : */
600 : :
601 : 2 : if (version == PVR_TYPE_P9)
602 : 0 : return add_memory_controller_p9n(msarea, arange);
603 : 2 : else if (version == PVR_TYPE_P9P)
604 : 0 : return; //return add_memory_controller_p9p(msarea, arange);
605 : : else
606 : 2 : return;
607 : : }
608 : :
609 : 1 : static void get_msareas(struct dt_node *root,
610 : : const struct HDIF_common_hdr *ms_vpd)
611 : : {
612 : : unsigned int i;
613 : : const struct HDIF_child_ptr *msptr;
614 : :
615 : : /* First childptr refers to msareas. */
616 : 1 : msptr = HDIF_child_arr(ms_vpd, MSVPD_CHILD_MS_AREAS);
617 : 1 : if (!CHECK_SPPTR(msptr)) {
618 : 0 : prerror("MS VPD: no children at %p\n", ms_vpd);
619 : 0 : return;
620 : : }
621 : :
622 : 3 : for (i = 0; i < be32_to_cpu(msptr->count); i++) {
623 : : const struct HDIF_common_hdr *msarea;
624 : : const struct HDIF_array_hdr *arr;
625 : : const struct HDIF_ms_area_address_range *arange;
626 : : const struct HDIF_ms_area_id *id;
627 : : const void *fruid;
628 : : unsigned int size, j, offset;
629 : : u16 flags;
630 : :
631 : 2 : msarea = HDIF_child(ms_vpd, msptr, i, "MSAREA");
632 : 2 : if (!CHECK_SPPTR(msarea))
633 : 0 : return;
634 : :
635 : 2 : id = HDIF_get_idata(msarea, 2, &size);
636 : 2 : if (!CHECK_SPPTR(id))
637 : 0 : return;
638 : 2 : if (size < sizeof(*id)) {
639 : 0 : prerror("MS VPD: %p msarea #%i id size too small!\n",
640 : : ms_vpd, i);
641 : 0 : return;
642 : : }
643 : :
644 : 2 : flags = be16_to_cpu(id->flags);
645 : 2 : prlog(PR_DEBUG, "MS VPD: %p, area %i: %s %s %s\n",
646 : : ms_vpd, i,
647 : : flags & MS_AREA_INSTALLED ?
648 : : "installed" : "not installed",
649 : : flags & MS_AREA_FUNCTIONAL ?
650 : : "functional" : "not functional",
651 : : flags & MS_AREA_SHARED ?
652 : : "shared" : "not shared");
653 : :
654 : 2 : if ((flags & (MS_AREA_INSTALLED|MS_AREA_FUNCTIONAL))
655 : : != (MS_AREA_INSTALLED|MS_AREA_FUNCTIONAL))
656 : 0 : continue;
657 : :
658 : 2 : arr = HDIF_get_idata(msarea, 4, &size);
659 : 2 : if (!CHECK_SPPTR(arr))
660 : 0 : continue;
661 : :
662 : 2 : if (size < sizeof(*arr)) {
663 : 0 : prerror("MS VPD: %p msarea #%i arr size too small!\n",
664 : : ms_vpd, i);
665 : 0 : return;
666 : : }
667 : :
668 : 2 : offset = offsetof(struct HDIF_ms_area_address_range, mirror_start);
669 : 2 : if (be32_to_cpu(arr->eactsz) < offset) {
670 : 0 : prerror("MS VPD: %p msarea #%i arange size too small!\n",
671 : : ms_vpd, i);
672 : 0 : return;
673 : : }
674 : :
675 : 2 : fruid = HDIF_get_idata(msarea, 0, &size);
676 : 2 : if (!CHECK_SPPTR(fruid))
677 : 0 : return;
678 : :
679 : : /* Add Raiser card VPD */
680 : 2 : if (be16_to_cpu(id->parent_type) & MS_PTYPE_RISER_CARD)
681 : 0 : dt_add_vpd_node(msarea, 0, 1);
682 : :
683 : : /* Add RAM Area VPD */
684 : 2 : vpd_add_ram_area(msarea);
685 : :
686 : 2 : add_memory_buffer_mmio(msarea);
687 : :
688 : : /* This offset is from the arr, not the header! */
689 : 2 : arange = (void *)arr + be32_to_cpu(arr->offset);
690 : 4 : for (j = 0; j < be32_to_cpu(arr->ecnt); j++) {
691 : 2 : uint32_t type = 0, status = 0;
692 : :
693 : : /*
694 : : * Check that the required fields are present in this
695 : : * version of the HDAT structure.
696 : : */
697 : 2 : offset = offsetof(struct HDIF_ms_area_address_range, controller_id);
698 : 2 : if (be32_to_cpu(arr->eactsz) >= offset)
699 : 2 : add_memory_controller(msarea, arange);
700 : :
701 : 2 : offset = offsetof(struct HDIF_ms_area_address_range, phys_attr);
702 : 2 : if (be32_to_cpu(arr->eactsz) >= offset) {
703 : 0 : uint32_t attr = be32_to_cpu(arange->phys_attr);
704 : :
705 : 0 : type = GETFIELD(PHYS_ATTR_TYPE_MASK, attr);
706 : 0 : status = GETFIELD(PHYS_ATTR_STATUS_MASK, attr);
707 : : }
708 : :
709 : 2 : if (!add_address_range(root, id, arange, type, status))
710 : 0 : prerror("Unable to use memory range %d from MSAREA %d\n", j, i);
711 : :
712 : 2 : arange = (void *)arange + be32_to_cpu(arr->esize);
713 : : }
714 : : }
715 : : }
716 : :
717 : : static struct dt_node *dt_hb_reserves;
718 : :
719 : 0 : static struct dt_node *add_hb_reserve_node(const char *name, u64 start, u64 end)
720 : : {
721 : : /* label size + "ibm," + NULL */
722 : 0 : char node_name[HB_RESERVE_MEM_LABEL_SIZE + 5] = { 0 };
723 : : struct dt_node *node, *hb;
724 : :
725 : 0 : if (!dt_hb_reserves) {
726 : 0 : hb = dt_new_check(dt_root, "ibm,hostboot");
727 : 0 : dt_add_property_cells(hb, "#size-cells", 2);
728 : 0 : dt_add_property_cells(hb, "#address-cells", 2);
729 : :
730 : 0 : dt_hb_reserves = dt_new_check(hb, "reserved-memory");
731 : 0 : dt_add_property(dt_hb_reserves, "ranges", NULL, 0);
732 : 0 : dt_add_property_cells(dt_hb_reserves, "#size-cells", 2);
733 : 0 : dt_add_property_cells(dt_hb_reserves, "#address-cells", 2);
734 : : }
735 : :
736 : : /* Add "ibm," to reserved node name */
737 : 0 : if (strncasecmp(name, "ibm", 3))
738 : 0 : snprintf(node_name, 5, "ibm,");
739 : 0 : strcat(node_name, name);
740 : :
741 : 0 : node = dt_new_addr(dt_hb_reserves, node_name, start);
742 : 0 : if (!node) {
743 : 0 : prerror("Unable to create node for %s@%llx\n",
744 : : node_name, (unsigned long long) start);
745 : 0 : return NULL;
746 : : }
747 : :
748 : 0 : dt_add_property_u64s(node, "reg", start, end - start + 1);
749 : :
750 : 0 : return node;
751 : : }
752 : :
753 : 1 : static void get_hb_reserved_mem(struct HDIF_common_hdr *ms_vpd)
754 : : {
755 : : const struct msvpd_hb_reserved_mem *hb_resv_mem;
756 : : u64 start_addr, end_addr, label_size;
757 : : struct dt_node *node;
758 : : int count, i;
759 : : char label[HB_RESERVE_MEM_LABEL_SIZE + 1];
760 : :
761 : : /*
762 : : * XXX: Reservation names only exist on P9 and on P7/8 we get the
763 : : * reserved ranges through the hostboot mini-FDT instead.
764 : : */
765 : 1 : if (proc_gen < proc_gen_p9)
766 : 1 : return;
767 : :
768 : 0 : count = HDIF_get_iarray_size(ms_vpd, MSVPD_IDATA_HB_RESERVED_MEM);
769 : 0 : if (count <= 0) {
770 : 0 : prerror("MS VPD: No hostboot reserved memory found\n");
771 : 0 : return;
772 : : }
773 : :
774 : 0 : for (i = 0; i < count; i++) {
775 : 0 : hb_resv_mem = HDIF_get_iarray_item(ms_vpd,
776 : : MSVPD_IDATA_HB_RESERVED_MEM,
777 : : i, NULL);
778 : 0 : if (!CHECK_SPPTR(hb_resv_mem))
779 : 0 : continue;
780 : :
781 : 0 : label_size = be32_to_cpu(hb_resv_mem->label_size);
782 : 0 : start_addr = be64_to_cpu(hb_resv_mem->start_addr);
783 : 0 : end_addr = be64_to_cpu(hb_resv_mem->end_addr);
784 : :
785 : : /* Zero length regions are a normal, but should be ignored */
786 : 0 : if (start_addr - end_addr == 0) {
787 : 0 : prlog(PR_DEBUG, "MEM: Ignoring zero length range\n");
788 : 0 : continue;
789 : : }
790 : :
791 : : /*
792 : : * Workaround broken HDAT reserve regions which are
793 : : * bigger than 512MB
794 : : */
795 : 0 : if ((end_addr - start_addr) > 0x20000000) {
796 : 0 : prlog(PR_ERR, "MEM: Ignoring Bad HDAT reserve: too big\n");
797 : 0 : continue;
798 : : }
799 : :
800 : : /* remove the HRMOR bypass bit */
801 : 0 : start_addr &= ~HRMOR_BIT;
802 : 0 : end_addr &= ~HRMOR_BIT;
803 : 0 : if (label_size > HB_RESERVE_MEM_LABEL_SIZE)
804 : 0 : label_size = HB_RESERVE_MEM_LABEL_SIZE;
805 : :
806 : 0 : memset(label, 0, HB_RESERVE_MEM_LABEL_SIZE + 1);
807 : 0 : memcpy(label, hb_resv_mem->label, label_size);
808 : 0 : label[label_size] = '\0';
809 : :
810 : : /* Unnamed reservations are always broken. Ignore them. */
811 : 0 : if (strlen(label) == 0)
812 : 0 : continue;
813 : :
814 : 0 : prlog(PR_DEBUG, "MEM: Reserve '%s' %#" PRIx64 "-%#" PRIx64 " (type/inst=0x%08x)\n",
815 : : label, start_addr, end_addr, be32_to_cpu(hb_resv_mem->type_instance));
816 : :
817 : 0 : node = add_hb_reserve_node(label, start_addr, end_addr);
818 : 0 : if (!node) {
819 : 0 : prerror("unable to add node?\n");
820 : 0 : continue;
821 : : }
822 : :
823 : : /* the three low bytes of type_instance is the instance data */
824 : 0 : dt_add_property_cells(node, "ibm,prd-instance",
825 : : (be32_to_cpu(hb_resv_mem->type_instance) & 0xffffff));
826 : :
827 : : /*
828 : : * Most reservations are used by HBRT itself so we should leave
829 : : * the label as-is. The exception is hbrt-code-image which is
830 : : * used by opal-prd to locate the HBRT image. Older versions
831 : : * of opal-prd expect this to be "ibm,hbrt-code-image" so make
832 : : * sure the prefix is there.
833 : : */
834 : 0 : if (!strcmp(label, "hbrt-code-image"))
835 : 0 : strcpy(label, "ibm,hbrt-code-image");
836 : 0 : dt_add_property_string(node, "ibm,prd-label", label);
837 : : }
838 : : }
839 : :
840 : 1 : static void parse_trace_reservations(struct HDIF_common_hdr *ms_vpd)
841 : : {
842 : : unsigned int size;
843 : : int count, i;
844 : :
845 : : /*
846 : : * The trace arrays are only setup when hostboot is explicitly
847 : : * configured to enable them. We need to check and gracefully handle
848 : : * when they're not present.
849 : : */
850 : :
851 : 1 : if (!HDIF_get_idata(ms_vpd, MSVPD_IDATA_TRACE_AREAS, &size) || !size) {
852 : 0 : prlog(PR_DEBUG, "MS VPD: No trace areas found\n");
853 : 1 : return;
854 : : }
855 : :
856 : 1 : count = HDIF_get_iarray_size(ms_vpd, MSVPD_IDATA_TRACE_AREAS);
857 : 1 : if (count <= 0) {
858 : 1 : prlog(PR_DEBUG, "MS VPD: No trace areas found\n");
859 : 1 : return;
860 : : }
861 : :
862 : 0 : prlog(PR_INFO, "MS VPD: Found %d trace areas\n", count);
863 : :
864 : 0 : for (i = 0; i < count; i++) {
865 : : const struct msvpd_trace *trace_area;
866 : : struct dt_node *node;
867 : : u64 start, end;
868 : :
869 : 0 : trace_area = HDIF_get_iarray_item(ms_vpd,
870 : : MSVPD_IDATA_TRACE_AREAS, i, &size);
871 : :
872 : 0 : if (!trace_area)
873 : 0 : return; /* shouldn't happen */
874 : :
875 : 0 : start = be64_to_cpu(trace_area->start) & ~HRMOR_BIT;
876 : 0 : end = be64_to_cpu(trace_area->end) & ~HRMOR_BIT;
877 : :
878 : 0 : prlog(PR_INFO,
879 : : "MS VPD: Trace area: 0x%.16"PRIx64"-0x%.16"PRIx64"\n",
880 : : start, end);
881 : :
882 : 0 : node = add_hb_reserve_node("trace-area", start, end);
883 : 0 : if (!node) {
884 : 0 : prerror("MEM: Unable to reserve trace area %p-%p\n",
885 : : (void *) start, (void *) end);
886 : 0 : continue;
887 : : }
888 : :
889 : 0 : dt_add_property(node, "no-map", NULL, 0);
890 : : }
891 : : }
892 : :
893 : 1 : static bool __memory_parse(struct dt_node *root)
894 : : {
895 : : struct HDIF_common_hdr *ms_vpd;
896 : : const struct msvpd_ms_addr_config *msac;
897 : : const struct msvpd_total_config_ms *tcms;
898 : : unsigned int size;
899 : :
900 : 1 : ms_vpd = get_hdif(&spiras->ntuples.ms_vpd, MSVPD_HDIF_SIG);
901 : 1 : if (!ms_vpd) {
902 : 0 : prerror("MS VPD: invalid\n");
903 : 0 : op_display(OP_FATAL, OP_MOD_MEM, 0x0000);
904 : 0 : return false;
905 : : }
906 : 1 : if (be32_to_cpu(spiras->ntuples.ms_vpd.act_len) < sizeof(*ms_vpd)) {
907 : 0 : prerror("MS VPD: invalid size %u\n",
908 : : be32_to_cpu(spiras->ntuples.ms_vpd.act_len));
909 : 0 : op_display(OP_FATAL, OP_MOD_MEM, 0x0001);
910 : 0 : return false;
911 : : }
912 : :
913 : 1 : prlog(PR_DEBUG, "MS VPD: is at %p\n", ms_vpd);
914 : :
915 : 1 : msac = HDIF_get_idata(ms_vpd, MSVPD_IDATA_MS_ADDR_CONFIG, &size);
916 : 1 : if (!CHECK_SPPTR(msac) ||
917 : 1 : size < offsetof(struct msvpd_ms_addr_config, max_possible_ms_address)) {
918 : 0 : prerror("MS VPD: bad msac size %u @ %p\n", size, msac);
919 : 0 : op_display(OP_FATAL, OP_MOD_MEM, 0x0002);
920 : 0 : return false;
921 : : }
922 : 1 : prlog(PR_DEBUG, "MS VPD: MSAC is at %p\n", msac);
923 : :
924 : 1 : dt_add_property_u64(dt_root, DT_PRIVATE "maxmem",
925 : 1 : be64_to_cpu(msac->max_configured_ms_address));
926 : :
927 : 1 : tcms = HDIF_get_idata(ms_vpd, MSVPD_IDATA_TOTAL_CONFIG_MS, &size);
928 : 1 : if (!CHECK_SPPTR(tcms) || size < sizeof(*tcms)) {
929 : 0 : prerror("MS VPD: Bad tcms size %u @ %p\n", size, tcms);
930 : 0 : op_display(OP_FATAL, OP_MOD_MEM, 0x0003);
931 : 0 : return false;
932 : : }
933 : 1 : prlog(PR_DEBUG, "MS VPD: TCMS is at %p\n", tcms);
934 : :
935 : 1 : prlog(PR_DEBUG, "MS VPD: Maximum configured address: 0x%llx\n",
936 : : (long long)be64_to_cpu(msac->max_configured_ms_address));
937 : 1 : prlog(PR_DEBUG, "MS VPD: Maximum possible address: 0x%llx\n",
938 : : (long long)be64_to_cpu(msac->max_possible_ms_address));
939 : :
940 : 1 : get_msareas(root, ms_vpd);
941 : :
942 : 1 : get_hb_reserved_mem(ms_vpd);
943 : :
944 : 1 : parse_trace_reservations(ms_vpd);
945 : :
946 : 1 : prlog(PR_INFO, "MS VPD: Total MB of RAM: 0x%llx\n",
947 : : (long long)be64_to_cpu(tcms->total_in_mb));
948 : :
949 : 1 : return true;
950 : : }
951 : :
952 : 1 : void memory_parse(void)
953 : : {
954 : 1 : if (!__memory_parse(dt_root)) {
955 : 0 : prerror("MS VPD: Failed memory init !\n");
956 : 0 : abort();
957 : : }
958 : 1 : }
|