blob: 10f3b737137c0f751320490e29cc0e7286e6fd92 [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 Shelley35171d92020-12-03 13:31:13 -0600311// IMPORTANT:
312// The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at some
313// point during the IPL. It is possible that this information is needed before
314// the sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600315uint32_t __getChipId(pdbg_target* i_trgt)
316{
317 uint32_t attr = 0;
318 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
319 return attr;
320}
321
Zane Shelley35171d92020-12-03 13:31:13 -0600322// IMPORTANT:
323// The ATTR_EC attribute will be synced from Hostboot to the BMC at some point
324// during the IPL. It is possible that this information is needed before the
325// sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600326uint8_t __getChipEc(pdbg_target* i_trgt)
327{
328 uint8_t attr = 0;
329 pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
330 return attr;
331}
332
333uint32_t __getChipIdEc(pdbg_target* i_trgt)
334{
Zane Shelley35171d92020-12-03 13:31:13 -0600335 auto chipId = __getChipId(i_trgt);
336 auto chipEc = __getChipEc(i_trgt);
337
338 if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt)))
339 {
340 // There is a special case where the model/level attributes have not
341 // been initialized in the devtree. This is possible on the epoch IPL
342 // where an attention occurs before Hostboot is able to update the
343 // devtree information on the BMC. It may is still possible to get this
344 // information from chips with CFAM access (i.e. a processor) via the
345 // CFAM chip ID register.
346
347 uint32_t val = 0;
348 if (0 == getCfam(i_trgt, 0x100a, val))
349 {
350 chipId = ((val & 0x0F0FF000) >> 12);
351 chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20);
352 }
353 }
354
355 return ((chipId & 0xffff) << 16) | (chipEc & 0xff);
Zane Shelley171a2e02020-11-13 13:56:13 -0600356}
357
358void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
359 libhei::ChipType_t i_type)
360{
361 // Trace each chip for debug. It is important to show the type just in case
362 // the model/EC does not exist. See note below.
363 trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
364 getPath(i_trgt));
365
366 if (0 == i_type)
367 {
Zane Shelley35171d92020-12-03 13:31:13 -0600368 // This is a special case. See the details in __getChipIdEC(). There is
369 // nothing more we can do with this chip since we don't know what it is.
370 // So ignore the chip for now.
Zane Shelley171a2e02020-11-13 13:56:13 -0600371 }
372 else
373 {
374 o_chips.emplace_back(i_trgt, i_type);
375 }
376}
377
378void getActiveChips(std::vector<libhei::Chip>& o_chips)
379{
380 o_chips.clear();
381
382 // Iterate each processor.
383 pdbg_target* procTrgt;
384 pdbg_for_each_class_target("proc", procTrgt)
385 {
386 // We cannot use the proc target to determine if the chip is active.
387 // There is some design limitation in pdbg that requires the proc
388 // targets to always be active. Instead, we must get the associated pib
389 // target and check if it is active.
390
391 // Active processors only.
392 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
393 continue;
394
395 // Add the processor to the list.
396 __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
397
398 // Iterate the connected OCMBs, if they exist.
399 pdbg_target* ocmbTrgt;
400 pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
401 {
402 // Active OCMBs only.
403 if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
404 continue;
405
406 // Add the OCMB to the list.
407 __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
408 }
409 }
410}
411
412//------------------------------------------------------------------------------
413
Zane Shelley3f363d42022-02-10 16:20:37 -0600414void getActiveProcessorChips(std::vector<pdbg_target*>& o_chips)
415{
416 o_chips.clear();
417
418 pdbg_target* procTrgt;
419 pdbg_for_each_class_target("proc", procTrgt)
420 {
421 // We cannot use the proc target to determine if the chip is active.
422 // There is some design limitation in pdbg that requires the proc
423 // targets to always be active. Instead, we must get the associated pib
424 // target and check if it is active.
425
426 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
427 continue;
428
429 o_chips.push_back(procTrgt);
430 }
431}
432
433//------------------------------------------------------------------------------
434
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600435pdbg_target* getPrimaryProcessor()
436{
437 // TODO: For at least P10, the primary processor (the one connected directly
438 // to the BMC), will always be PROC 0. We will need to update this
439 // later if we ever support an alternate primary processor.
440 return getTrgt("/proc0");
441}
442
443//------------------------------------------------------------------------------
444
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600445bool queryHardwareAnalysisSupported()
446{
447 // Hardware analysis is only supported on P10 systems and up.
Zane Shelley5183af32020-12-07 14:49:03 -0600448 return (PDBG_PROC_P9 < pdbg_get_proc());
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600449}
450
451//------------------------------------------------------------------------------
452
Zane Shelley3a851082021-03-23 16:45:28 -0500453std::string getLocationCode(pdbg_target* trgt)
454{
455 if (nullptr == trgt)
456 {
457 // Either the path is wrong or the attribute doesn't exist.
458 return std::string{};
459 }
460
461#ifdef CONFIG_PHAL_API
462
463 ATTR_LOCATION_CODE_Type val;
464 if (DT_GET_PROP(ATTR_LOCATION_CODE, trgt, val))
465 {
466 // Get the immediate parent in the devtree path and try again.
467 return getLocationCode(pdbg_target_parent(nullptr, trgt));
468 }
469
470 // Attribute found.
471 return std::string{val};
472
473#else
474
475 return std::string{getPath(trgt)};
476
477#endif
478}
479
480//------------------------------------------------------------------------------
481
482std::string getPhysDevPath(pdbg_target* trgt)
483{
484 if (nullptr == trgt)
485 {
486 // Either the path is wrong or the attribute doesn't exist.
487 return std::string{};
488 }
489
490#ifdef CONFIG_PHAL_API
491
492 ATTR_PHYS_DEV_PATH_Type val;
493 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, trgt, val))
494 {
495 // Get the immediate parent in the devtree path and try again.
496 return getPhysDevPath(pdbg_target_parent(nullptr, trgt));
497 }
498
499 // Attribute found.
500 return std::string{val};
501
502#else
503
504 return std::string{getPath(trgt)};
505
506#endif
507}
508
509//------------------------------------------------------------------------------
510
Zane Shelleybf3326f2021-11-12 13:41:39 -0600511std::vector<uint8_t> getPhysBinPath(pdbg_target* target)
512{
513 std::vector<uint8_t> binPath;
514
515 if (nullptr != target)
516 {
517#ifdef CONFIG_PHAL_API
518
519 ATTR_PHYS_BIN_PATH_Type value;
520 if (DT_GET_PROP(ATTR_PHYS_BIN_PATH, target, value))
521 {
522 // The attrirbute for this target does not exist. Get the immediate
523 // parent in the devtree path and try again. Note that if there is
524 // no parent target, nullptr will be returned and that will be
525 // checked above.
526 return getPhysBinPath(pdbg_target_parent(nullptr, target));
527 }
528
529 // Attribute was found. Copy the attribute array to the returned
530 // vector. Note that the reason we return the vector instead of just
531 // returning the array is because the array type and details only
532 // exists in this specific configuration.
533 binPath.insert(binPath.end(), value, value + sizeof(value));
534
535#endif
536 }
537
538 return binPath;
539}
540
541//------------------------------------------------------------------------------
542
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -0600543} // namespace pdbg
544
545} // namespace util