blob: c798240a412e01200465008fd2029e149f3dcbbd [file] [log] [blame]
Zane Shelleye90b85d2021-12-17 17:24:49 -06001//------------------------------------------------------------------------------
2// IMPORTANT:
3// This file will be built in CI test and should work out-of-the-box in CI test
4// with use of the fake device tree. Any functions that require addition support
5// to simulate in CI test should be put in `pdbg_no_sim.cpp`.
6//------------------------------------------------------------------------------
7
Zane Shelley171a2e02020-11-13 13:56:13 -06008#include <assert.h>
Zane Shelleye4bfb472021-08-10 12:47:32 -05009#include <config.h>
Zane Shelley171a2e02020-11-13 13:56:13 -060010
Zane Shelley7ae9c8c2020-12-02 20:10:31 -060011#include <hei_main.hpp>
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060012#include <util/pdbg.hpp>
Zane Shelley171a2e02020-11-13 13:56:13 -060013#include <util/trace.hpp>
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060014
Zane Shelley3a851082021-03-23 16:45:28 -050015#ifdef CONFIG_PHAL_API
Zane Shelleye4bfb472021-08-10 12:47:32 -050016#include <attributes_info.H>
Zane Shelley3a851082021-03-23 16:45:28 -050017#endif
18
Zane Shelley38501e12022-01-10 15:42:28 -060019using namespace analyzer;
20
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060021namespace util
22{
23
24namespace pdbg
25{
26
27//------------------------------------------------------------------------------
28
Zane Shelleya0299852020-11-13 13:38:04 -060029pdbg_target* getTrgt(const libhei::Chip& i_chip)
30{
31 return (pdbg_target*)i_chip.getChip();
32}
33
34//------------------------------------------------------------------------------
35
Zane Shelley236bb732021-03-24 17:07:46 -050036pdbg_target* getTrgt(const std::string& i_path)
37{
38 return pdbg_target_from_path(nullptr, i_path.c_str());
39}
40
41//------------------------------------------------------------------------------
42
Zane Shelleya0299852020-11-13 13:38:04 -060043const char* getPath(pdbg_target* i_trgt)
44{
45 return pdbg_target_path(i_trgt);
46}
47
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060048const char* getPath(const libhei::Chip& i_chip)
49{
Zane Shelleya0299852020-11-13 13:38:04 -060050 return getPath(getTrgt(i_chip));
51}
52
53//------------------------------------------------------------------------------
54
55uint32_t getChipPos(pdbg_target* i_trgt)
56{
57 uint32_t attr = 0;
58 pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr);
59 return attr;
60}
61
62uint32_t getChipPos(const libhei::Chip& i_chip)
63{
64 return getChipPos(getTrgt(i_chip));
65}
66
67//------------------------------------------------------------------------------
68
Zane Shelley2a394cb2022-02-17 22:01:39 -060069uint8_t getUnitPos(pdbg_target* i_trgt)
70{
71 uint8_t attr = 0;
72 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_UNIT_POS", 1, 1, &attr);
73 return attr;
74}
75
76//------------------------------------------------------------------------------
77
Zane Shelleya0299852020-11-13 13:38:04 -060078uint8_t getTrgtType(pdbg_target* i_trgt)
79{
80 uint8_t attr = 0;
81 pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr);
82 return attr;
83}
84
85uint8_t getTrgtType(const libhei::Chip& i_chip)
86{
87 return getTrgtType(getTrgt(i_chip));
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060088}
89
90//------------------------------------------------------------------------------
91
Zane Shelley2a394cb2022-02-17 22:01:39 -060092pdbg_target* getParentChip(pdbg_target* i_unitTarget)
93{
94 assert(nullptr != i_unitTarget);
95
96 // Check if the given target is already a chip.
97 auto targetType = getTrgtType(i_unitTarget);
98 if (TYPE_PROC == targetType || TYPE_OCMB == targetType)
99 {
100 return i_unitTarget; // simply return the given target
101 }
102
103 // Check if this unit is on an OCMB.
104 pdbg_target* parentChip = pdbg_target_parent("ocmb", i_unitTarget);
105
106 // If not on the OCMB, check if this unit is on a PROC.
107 if (nullptr == parentChip)
108 {
109 parentChip = pdbg_target_parent("proc", i_unitTarget);
110 }
111
112 // There should always be a parent chip. Throw an error if not found.
113 if (nullptr == parentChip)
114 {
115 throw std::logic_error("No parent chip found: i_unitTarget=" +
116 std::string{getPath(i_unitTarget)});
117 }
118
119 return parentChip;
120}
121
122//------------------------------------------------------------------------------
123
124pdbg_target* getChipUnit(pdbg_target* i_parentChip, TargetType_t i_unitType,
125 uint8_t i_unitPos)
126{
127 assert(nullptr != i_parentChip);
128
129 auto parentType = getTrgtType(i_parentChip);
130
131 std::string devTreeType{};
132
133 if (TYPE_PROC == parentType)
134 {
135 // clang-format off
136 static const std::map<TargetType_t, std::string> m =
137 {
138 {TYPE_MC, "mc" },
139 {TYPE_MCC, "mcc" },
140 {TYPE_OMI, "omi" },
141 {TYPE_OMIC, "omic" },
142 {TYPE_PAUC, "pauc" },
143 {TYPE_PAU, "pau" },
144 {TYPE_NMMU, "nmmu" },
145 {TYPE_IOHS, "iohs" },
146 {TYPE_IOLINK, "smpgroup"},
147 {TYPE_EQ, "eq" },
148 {TYPE_CORE, "core" },
149 {TYPE_PEC, "pec" },
150 {TYPE_PHB, "phb" },
151 {TYPE_NX, "nx" },
152 };
153 // clang-format on
154
155 devTreeType = m.at(i_unitType);
156 }
157 else if (TYPE_OCMB == parentType)
158 {
159 // clang-format off
160 static const std::map<TargetType_t, std::string> m =
161 {
162 {TYPE_MEM_PORT, "mem_port"},
163 };
164 // clang-format on
165
166 devTreeType = m.at(i_unitType);
167 }
168 else
169 {
170 throw std::logic_error("Unexpected parent chip: " +
171 std::string{getPath(i_parentChip)});
172 }
173
174 // Iterate all children of the parent and match the unit position.
175 pdbg_target* unitTarget = nullptr;
176 pdbg_for_each_target(devTreeType.c_str(), i_parentChip, unitTarget)
177 {
178 if (nullptr != unitTarget && i_unitPos == getUnitPos(unitTarget))
179 {
180 break; // found it
181 }
182 }
183
184 // Print a warning if the target unit is not found, but don't throw an
185 // error. Instead let the calling code deal with the it.
186 if (nullptr == unitTarget)
187 {
188 trace::err("No unit target found: i_parentChip=%s i_unitType=0x%02x "
189 "i_unitPos=%u",
190 getPath(i_parentChip), i_unitType, i_unitPos);
191 }
192
193 return unitTarget;
194}
195
196//------------------------------------------------------------------------------
197
Zane Shelley38501e12022-01-10 15:42:28 -0600198pdbg_target* getConnectedTarget(pdbg_target* i_rxTarget,
199 const callout::BusType& i_busType)
200{
201 assert(nullptr != i_rxTarget);
202
203 pdbg_target* txTarget = nullptr;
204
205 auto rxType = util::pdbg::getTrgtType(i_rxTarget);
206 std::string rxPath = util::pdbg::getPath(i_rxTarget);
207
208 if (callout::BusType::SMP_BUS == i_busType &&
209 util::pdbg::TYPE_IOLINK == rxType)
210 {
211 // TODO: Will need to reference some sort of data that can tell us how
212 // the processors are connected in the system. For now, return the
213 // RX target to avoid returning a nullptr.
214 trace::inf("No support to get peer target on SMP bus");
215 txTarget = i_rxTarget;
216 }
217 else if (callout::BusType::SMP_BUS == i_busType &&
218 util::pdbg::TYPE_IOHS == rxType)
219 {
220 // TODO: Will need to reference some sort of data that can tell us how
221 // the processors are connected in the system. For now, return the
222 // RX target to avoid returning a nullptr.
223 trace::inf("No support to get peer target on SMP bus");
224 txTarget = i_rxTarget;
225 }
226 else if (callout::BusType::OMI_BUS == i_busType &&
227 util::pdbg::TYPE_OMI == rxType)
228 {
229 // This is a bit clunky. The pdbg APIs only give us the ability to
230 // iterate over the children instead of just returning a list. So we'll
231 // push all the children to a list and go from there.
232 std::vector<pdbg_target*> childList;
233
234 pdbg_target* childTarget = nullptr;
235 pdbg_for_each_target("ocmb", i_rxTarget, childTarget)
236 {
237 if (nullptr != childTarget)
238 {
239 childList.push_back(childTarget);
240 }
241 }
242
243 // We know there should only be one OCMB per OMI.
244 if (1 != childList.size())
245 {
246 throw std::logic_error("Invalid child list size for " + rxPath);
247 }
248
249 // Get the connected target.
250 txTarget = childList.front();
251 }
252 else if (callout::BusType::OMI_BUS == i_busType &&
253 util::pdbg::TYPE_OCMB == rxType)
254 {
255 txTarget = pdbg_target_parent("omi", i_rxTarget);
256 if (nullptr == txTarget)
257 {
258 throw std::logic_error("No parent OMI found for " + rxPath);
259 }
260 }
261 else
262 {
263 // This would be a code bug.
264 throw std::logic_error("Unsupported config: i_rxTarget=" + rxPath +
265 " i_busType=" + i_busType.getString());
266 }
267
268 assert(nullptr != txTarget); // just in case we missed something above
269
270 return txTarget;
271}
272
273//------------------------------------------------------------------------------
274
Zane Shelley171a2e02020-11-13 13:56:13 -0600275pdbg_target* getPibTrgt(pdbg_target* i_procTrgt)
276{
277 // The input target must be a processor.
Zane Shelley35171d92020-12-03 13:31:13 -0600278 assert(TYPE_PROC == getTrgtType(i_procTrgt));
Zane Shelley171a2e02020-11-13 13:56:13 -0600279
280 // Get the pib path.
281 char path[16];
282 sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
283
284 // Return the pib target.
285 pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path);
286 assert(nullptr != pibTrgt);
287
288 return pibTrgt;
289}
290
291//------------------------------------------------------------------------------
292
Zane Shelleyff76b6b2020-11-18 13:54:26 -0600293pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt)
294{
295 // The input target must be a processor.
Zane Shelley35171d92020-12-03 13:31:13 -0600296 assert(TYPE_PROC == getTrgtType(i_procTrgt));
Zane Shelleyff76b6b2020-11-18 13:54:26 -0600297
298 // Get the fsi path.
299 char path[16];
300 sprintf(path, "/proc%d/fsi", pdbg_target_index(i_procTrgt));
301
302 // Return the fsi target.
303 pdbg_target* fsiTrgt = pdbg_target_from_path(nullptr, path);
304 assert(nullptr != fsiTrgt);
305
306 return fsiTrgt;
307}
308
309//------------------------------------------------------------------------------
310
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600311int getScom(pdbg_target* i_trgt, uint64_t i_addr, uint64_t& o_val)
312{
313 // Only processor targets are supported.
314 // TODO: Will need to add OCMB support later.
315 assert(TYPE_PROC == getTrgtType(i_trgt));
316
317 auto pibTrgt = util::pdbg::getPibTrgt(i_trgt);
318
319 int rc = pib_read(pibTrgt, i_addr, &o_val);
320
321 if (0 != rc)
322 {
323 trace::err("pib_read failure: target=%s addr=0x%0" PRIx64,
324 util::pdbg::getPath(pibTrgt), i_addr);
325 }
326
327 return rc;
328}
329
330//------------------------------------------------------------------------------
331
Zane Shelley35171d92020-12-03 13:31:13 -0600332int getCfam(pdbg_target* i_trgt, uint32_t i_addr, uint32_t& o_val)
333{
334 // Only processor targets are supported.
335 assert(TYPE_PROC == getTrgtType(i_trgt));
336
337 auto fsiTrgt = util::pdbg::getFsiTrgt(i_trgt);
338
339 int rc = fsi_read(fsiTrgt, i_addr, &o_val);
340
341 if (0 != rc)
342 {
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600343 trace::err("fsi_read failure: target=%s addr=0x%08x",
Zane Shelley35171d92020-12-03 13:31:13 -0600344 util::pdbg::getPath(fsiTrgt), i_addr);
345 }
346
347 return rc;
348}
349
350//------------------------------------------------------------------------------
351
352// IMPORTANT:
353// The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at some
354// point during the IPL. It is possible that this information is needed before
355// the sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600356uint32_t __getChipId(pdbg_target* i_trgt)
357{
358 uint32_t attr = 0;
359 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
360 return attr;
361}
362
Zane Shelley35171d92020-12-03 13:31:13 -0600363// IMPORTANT:
364// The ATTR_EC attribute will be synced from Hostboot to the BMC at some point
365// during the IPL. It is possible that this information is needed before the
366// sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600367uint8_t __getChipEc(pdbg_target* i_trgt)
368{
369 uint8_t attr = 0;
370 pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
371 return attr;
372}
373
374uint32_t __getChipIdEc(pdbg_target* i_trgt)
375{
Zane Shelley35171d92020-12-03 13:31:13 -0600376 auto chipId = __getChipId(i_trgt);
377 auto chipEc = __getChipEc(i_trgt);
378
379 if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt)))
380 {
381 // There is a special case where the model/level attributes have not
382 // been initialized in the devtree. This is possible on the epoch IPL
383 // where an attention occurs before Hostboot is able to update the
384 // devtree information on the BMC. It may is still possible to get this
385 // information from chips with CFAM access (i.e. a processor) via the
386 // CFAM chip ID register.
387
388 uint32_t val = 0;
389 if (0 == getCfam(i_trgt, 0x100a, val))
390 {
391 chipId = ((val & 0x0F0FF000) >> 12);
392 chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20);
393 }
394 }
395
396 return ((chipId & 0xffff) << 16) | (chipEc & 0xff);
Zane Shelley171a2e02020-11-13 13:56:13 -0600397}
398
399void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
400 libhei::ChipType_t i_type)
401{
402 // Trace each chip for debug. It is important to show the type just in case
403 // the model/EC does not exist. See note below.
404 trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
405 getPath(i_trgt));
406
407 if (0 == i_type)
408 {
Zane Shelley35171d92020-12-03 13:31:13 -0600409 // This is a special case. See the details in __getChipIdEC(). There is
410 // nothing more we can do with this chip since we don't know what it is.
411 // So ignore the chip for now.
Zane Shelley171a2e02020-11-13 13:56:13 -0600412 }
413 else
414 {
415 o_chips.emplace_back(i_trgt, i_type);
416 }
417}
418
419void getActiveChips(std::vector<libhei::Chip>& o_chips)
420{
421 o_chips.clear();
422
423 // Iterate each processor.
424 pdbg_target* procTrgt;
425 pdbg_for_each_class_target("proc", procTrgt)
426 {
427 // We cannot use the proc target to determine if the chip is active.
428 // There is some design limitation in pdbg that requires the proc
429 // targets to always be active. Instead, we must get the associated pib
430 // target and check if it is active.
431
432 // Active processors only.
433 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
434 continue;
435
436 // Add the processor to the list.
437 __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
438
439 // Iterate the connected OCMBs, if they exist.
440 pdbg_target* ocmbTrgt;
441 pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
442 {
443 // Active OCMBs only.
444 if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
445 continue;
446
447 // Add the OCMB to the list.
448 __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
449 }
450 }
451}
452
453//------------------------------------------------------------------------------
454
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600455pdbg_target* getPrimaryProcessor()
456{
457 // TODO: For at least P10, the primary processor (the one connected directly
458 // to the BMC), will always be PROC 0. We will need to update this
459 // later if we ever support an alternate primary processor.
460 return getTrgt("/proc0");
461}
462
463//------------------------------------------------------------------------------
464
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600465bool queryHardwareAnalysisSupported()
466{
467 // Hardware analysis is only supported on P10 systems and up.
Zane Shelley5183af32020-12-07 14:49:03 -0600468 return (PDBG_PROC_P9 < pdbg_get_proc());
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600469}
470
471//------------------------------------------------------------------------------
472
Zane Shelley3a851082021-03-23 16:45:28 -0500473std::string getLocationCode(pdbg_target* trgt)
474{
475 if (nullptr == trgt)
476 {
477 // Either the path is wrong or the attribute doesn't exist.
478 return std::string{};
479 }
480
481#ifdef CONFIG_PHAL_API
482
483 ATTR_LOCATION_CODE_Type val;
484 if (DT_GET_PROP(ATTR_LOCATION_CODE, trgt, val))
485 {
486 // Get the immediate parent in the devtree path and try again.
487 return getLocationCode(pdbg_target_parent(nullptr, trgt));
488 }
489
490 // Attribute found.
491 return std::string{val};
492
493#else
494
495 return std::string{getPath(trgt)};
496
497#endif
498}
499
500//------------------------------------------------------------------------------
501
502std::string getPhysDevPath(pdbg_target* trgt)
503{
504 if (nullptr == trgt)
505 {
506 // Either the path is wrong or the attribute doesn't exist.
507 return std::string{};
508 }
509
510#ifdef CONFIG_PHAL_API
511
512 ATTR_PHYS_DEV_PATH_Type val;
513 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, trgt, val))
514 {
515 // Get the immediate parent in the devtree path and try again.
516 return getPhysDevPath(pdbg_target_parent(nullptr, trgt));
517 }
518
519 // Attribute found.
520 return std::string{val};
521
522#else
523
524 return std::string{getPath(trgt)};
525
526#endif
527}
528
529//------------------------------------------------------------------------------
530
Zane Shelleybf3326f2021-11-12 13:41:39 -0600531std::vector<uint8_t> getPhysBinPath(pdbg_target* target)
532{
533 std::vector<uint8_t> binPath;
534
535 if (nullptr != target)
536 {
537#ifdef CONFIG_PHAL_API
538
539 ATTR_PHYS_BIN_PATH_Type value;
540 if (DT_GET_PROP(ATTR_PHYS_BIN_PATH, target, value))
541 {
542 // The attrirbute for this target does not exist. Get the immediate
543 // parent in the devtree path and try again. Note that if there is
544 // no parent target, nullptr will be returned and that will be
545 // checked above.
546 return getPhysBinPath(pdbg_target_parent(nullptr, target));
547 }
548
549 // Attribute was found. Copy the attribute array to the returned
550 // vector. Note that the reason we return the vector instead of just
551 // returning the array is because the array type and details only
552 // exists in this specific configuration.
553 binPath.insert(binPath.end(), value, value + sizeof(value));
554
555#endif
556 }
557
558 return binPath;
559}
560
561//------------------------------------------------------------------------------
562
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -0600563} // namespace pdbg
564
565} // namespace util