blob: 46bb37bd1b8f1b92c1975b94380ad9ba820796c7 [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>
Caleb Palmer626270a2022-02-21 11:05:08 -060012#include <nlohmann/json.hpp>
13#include <util/dbus.hpp>
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060014#include <util/pdbg.hpp>
Zane Shelley171a2e02020-11-13 13:56:13 -060015#include <util/trace.hpp>
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060016
Caleb Palmer626270a2022-02-21 11:05:08 -060017#include <filesystem>
18#include <fstream>
19#include <string>
20
Zane Shelley3a851082021-03-23 16:45:28 -050021#ifdef CONFIG_PHAL_API
Zane Shelleye4bfb472021-08-10 12:47:32 -050022#include <attributes_info.H>
Zane Shelley3a851082021-03-23 16:45:28 -050023#endif
24
Zane Shelley38501e12022-01-10 15:42:28 -060025using namespace analyzer;
26
Caleb Palmer626270a2022-02-21 11:05:08 -060027namespace fs = std::filesystem;
28
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060029namespace util
30{
31
32namespace pdbg
33{
34
35//------------------------------------------------------------------------------
36
Zane Shelleya0299852020-11-13 13:38:04 -060037pdbg_target* getTrgt(const libhei::Chip& i_chip)
38{
39 return (pdbg_target*)i_chip.getChip();
40}
41
42//------------------------------------------------------------------------------
43
Zane Shelley236bb732021-03-24 17:07:46 -050044pdbg_target* getTrgt(const std::string& i_path)
45{
46 return pdbg_target_from_path(nullptr, i_path.c_str());
47}
48
49//------------------------------------------------------------------------------
50
Zane Shelleya0299852020-11-13 13:38:04 -060051const char* getPath(pdbg_target* i_trgt)
52{
53 return pdbg_target_path(i_trgt);
54}
55
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060056const char* getPath(const libhei::Chip& i_chip)
57{
Zane Shelleya0299852020-11-13 13:38:04 -060058 return getPath(getTrgt(i_chip));
59}
60
61//------------------------------------------------------------------------------
62
63uint32_t getChipPos(pdbg_target* i_trgt)
64{
65 uint32_t attr = 0;
66 pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr);
67 return attr;
68}
69
70uint32_t getChipPos(const libhei::Chip& i_chip)
71{
72 return getChipPos(getTrgt(i_chip));
73}
74
75//------------------------------------------------------------------------------
76
Zane Shelley2a394cb2022-02-17 22:01:39 -060077uint8_t getUnitPos(pdbg_target* i_trgt)
78{
79 uint8_t attr = 0;
80 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_UNIT_POS", 1, 1, &attr);
81 return attr;
82}
83
84//------------------------------------------------------------------------------
85
Zane Shelleya0299852020-11-13 13:38:04 -060086uint8_t getTrgtType(pdbg_target* i_trgt)
87{
88 uint8_t attr = 0;
89 pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr);
90 return attr;
91}
92
93uint8_t getTrgtType(const libhei::Chip& i_chip)
94{
95 return getTrgtType(getTrgt(i_chip));
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -060096}
97
98//------------------------------------------------------------------------------
99
Zane Shelley2a394cb2022-02-17 22:01:39 -0600100pdbg_target* getParentChip(pdbg_target* i_unitTarget)
101{
102 assert(nullptr != i_unitTarget);
103
104 // Check if the given target is already a chip.
105 auto targetType = getTrgtType(i_unitTarget);
106 if (TYPE_PROC == targetType || TYPE_OCMB == targetType)
107 {
108 return i_unitTarget; // simply return the given target
109 }
110
111 // Check if this unit is on an OCMB.
112 pdbg_target* parentChip = pdbg_target_parent("ocmb", i_unitTarget);
113
114 // If not on the OCMB, check if this unit is on a PROC.
115 if (nullptr == parentChip)
116 {
117 parentChip = pdbg_target_parent("proc", i_unitTarget);
118 }
119
120 // There should always be a parent chip. Throw an error if not found.
121 if (nullptr == parentChip)
122 {
123 throw std::logic_error("No parent chip found: i_unitTarget=" +
124 std::string{getPath(i_unitTarget)});
125 }
126
127 return parentChip;
128}
129
130//------------------------------------------------------------------------------
131
132pdbg_target* getChipUnit(pdbg_target* i_parentChip, TargetType_t i_unitType,
133 uint8_t i_unitPos)
134{
135 assert(nullptr != i_parentChip);
136
137 auto parentType = getTrgtType(i_parentChip);
138
139 std::string devTreeType{};
140
141 if (TYPE_PROC == parentType)
142 {
143 // clang-format off
144 static const std::map<TargetType_t, std::string> m =
145 {
146 {TYPE_MC, "mc" },
147 {TYPE_MCC, "mcc" },
148 {TYPE_OMI, "omi" },
149 {TYPE_OMIC, "omic" },
150 {TYPE_PAUC, "pauc" },
151 {TYPE_PAU, "pau" },
152 {TYPE_NMMU, "nmmu" },
153 {TYPE_IOHS, "iohs" },
154 {TYPE_IOLINK, "smpgroup"},
155 {TYPE_EQ, "eq" },
156 {TYPE_CORE, "core" },
157 {TYPE_PEC, "pec" },
158 {TYPE_PHB, "phb" },
159 {TYPE_NX, "nx" },
160 };
161 // clang-format on
162
163 devTreeType = m.at(i_unitType);
164 }
165 else if (TYPE_OCMB == parentType)
166 {
167 // clang-format off
168 static const std::map<TargetType_t, std::string> m =
169 {
170 {TYPE_MEM_PORT, "mem_port"},
171 };
172 // clang-format on
173
174 devTreeType = m.at(i_unitType);
175 }
176 else
177 {
178 throw std::logic_error("Unexpected parent chip: " +
179 std::string{getPath(i_parentChip)});
180 }
181
182 // Iterate all children of the parent and match the unit position.
183 pdbg_target* unitTarget = nullptr;
184 pdbg_for_each_target(devTreeType.c_str(), i_parentChip, unitTarget)
185 {
186 if (nullptr != unitTarget && i_unitPos == getUnitPos(unitTarget))
187 {
188 break; // found it
189 }
190 }
191
192 // Print a warning if the target unit is not found, but don't throw an
193 // error. Instead let the calling code deal with the it.
194 if (nullptr == unitTarget)
195 {
196 trace::err("No unit target found: i_parentChip=%s i_unitType=0x%02x "
197 "i_unitPos=%u",
198 getPath(i_parentChip), i_unitType, i_unitPos);
199 }
200
201 return unitTarget;
202}
203
204//------------------------------------------------------------------------------
205
Caleb Palmer626270a2022-02-21 11:05:08 -0600206pdbg_target* getTargetAcrossBus(pdbg_target* i_rxTarget)
207{
208 assert(nullptr != i_rxTarget);
209
210 // Validate target type
211 auto rxType = util::pdbg::getTrgtType(i_rxTarget);
212 assert(util::pdbg::TYPE_IOLINK == rxType ||
213 util::pdbg::TYPE_IOHS == rxType);
214
215 pdbg_target* o_peerTarget;
216 fs::path filePath;
217
218 // Open the appropriate data file depending on machine type
219 util::dbus::MachineType machineType = util::dbus::getMachineType();
220 switch (machineType)
221 {
222 // Rainier 4U
223 case util::dbus::MachineType::Rainier_2S4U:
224 case util::dbus::MachineType::Rainier_1S4U:
225 filePath =
226 fs::path{PACKAGE_DIR "util-data/peer-targets-rainier-4u.json"};
227 break;
228 // Rainier 2U
229 case util::dbus::MachineType::Rainier_2S2U:
230 case util::dbus::MachineType::Rainier_1S2U:
231 filePath =
232 fs::path{PACKAGE_DIR "util-data/peer-targets-rainier-2u.json"};
233 break;
234 // Everest
235 case util::dbus::MachineType::Everest:
236 filePath =
237 fs::path{PACKAGE_DIR "util-data/peer-targets-everest.json"};
238 break;
239 default:
240 trace::err("Invalid machine type found %d",
241 static_cast<uint8_t>(machineType));
242 break;
243 }
244
245 std::ifstream file{filePath};
246 assert(file.good());
247
248 try
249 {
250 auto trgtMap = nlohmann::json::parse(file);
251 std::string rxPath = util::pdbg::getPath(i_rxTarget);
252 std::string peerPath = trgtMap.at(rxPath).get<std::string>();
253
254 o_peerTarget = util::pdbg::getTrgt(peerPath);
255 }
256 catch (...)
257 {
258 trace::err("Failed to parse file: %s", filePath.string().c_str());
259 throw;
260 }
261
262 return o_peerTarget;
263}
264
265//------------------------------------------------------------------------------
266
Zane Shelley38501e12022-01-10 15:42:28 -0600267pdbg_target* getConnectedTarget(pdbg_target* i_rxTarget,
268 const callout::BusType& i_busType)
269{
270 assert(nullptr != i_rxTarget);
271
272 pdbg_target* txTarget = nullptr;
273
274 auto rxType = util::pdbg::getTrgtType(i_rxTarget);
275 std::string rxPath = util::pdbg::getPath(i_rxTarget);
276
277 if (callout::BusType::SMP_BUS == i_busType &&
278 util::pdbg::TYPE_IOLINK == rxType)
279 {
Caleb Palmer626270a2022-02-21 11:05:08 -0600280 txTarget = getTargetAcrossBus(i_rxTarget);
Zane Shelley38501e12022-01-10 15:42:28 -0600281 }
282 else if (callout::BusType::SMP_BUS == i_busType &&
283 util::pdbg::TYPE_IOHS == rxType)
284 {
Caleb Palmer626270a2022-02-21 11:05:08 -0600285 txTarget = getTargetAcrossBus(i_rxTarget);
Zane Shelley38501e12022-01-10 15:42:28 -0600286 }
287 else if (callout::BusType::OMI_BUS == i_busType &&
288 util::pdbg::TYPE_OMI == rxType)
289 {
290 // This is a bit clunky. The pdbg APIs only give us the ability to
Caleb Palmer626270a2022-02-21 11:05:08 -0600291 // iterate over the children instead of just returning a list. So
292 // we'll push all the children to a list and go from there.
Zane Shelley38501e12022-01-10 15:42:28 -0600293 std::vector<pdbg_target*> childList;
294
295 pdbg_target* childTarget = nullptr;
296 pdbg_for_each_target("ocmb", i_rxTarget, childTarget)
297 {
298 if (nullptr != childTarget)
299 {
300 childList.push_back(childTarget);
301 }
302 }
303
304 // We know there should only be one OCMB per OMI.
305 if (1 != childList.size())
306 {
307 throw std::logic_error("Invalid child list size for " + rxPath);
308 }
309
310 // Get the connected target.
311 txTarget = childList.front();
312 }
313 else if (callout::BusType::OMI_BUS == i_busType &&
314 util::pdbg::TYPE_OCMB == rxType)
315 {
316 txTarget = pdbg_target_parent("omi", i_rxTarget);
317 if (nullptr == txTarget)
318 {
319 throw std::logic_error("No parent OMI found for " + rxPath);
320 }
321 }
322 else
323 {
324 // This would be a code bug.
325 throw std::logic_error("Unsupported config: i_rxTarget=" + rxPath +
326 " i_busType=" + i_busType.getString());
327 }
328
329 assert(nullptr != txTarget); // just in case we missed something above
330
331 return txTarget;
332}
333
334//------------------------------------------------------------------------------
335
Zane Shelley171a2e02020-11-13 13:56:13 -0600336pdbg_target* getPibTrgt(pdbg_target* i_procTrgt)
337{
338 // The input target must be a processor.
Zane Shelley35171d92020-12-03 13:31:13 -0600339 assert(TYPE_PROC == getTrgtType(i_procTrgt));
Zane Shelley171a2e02020-11-13 13:56:13 -0600340
341 // Get the pib path.
342 char path[16];
343 sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
344
345 // Return the pib target.
346 pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path);
347 assert(nullptr != pibTrgt);
348
349 return pibTrgt;
350}
351
352//------------------------------------------------------------------------------
353
Zane Shelleyff76b6b2020-11-18 13:54:26 -0600354pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt)
355{
356 // The input target must be a processor.
Zane Shelley35171d92020-12-03 13:31:13 -0600357 assert(TYPE_PROC == getTrgtType(i_procTrgt));
Zane Shelleyff76b6b2020-11-18 13:54:26 -0600358
359 // Get the fsi path.
360 char path[16];
361 sprintf(path, "/proc%d/fsi", pdbg_target_index(i_procTrgt));
362
363 // Return the fsi target.
364 pdbg_target* fsiTrgt = pdbg_target_from_path(nullptr, path);
365 assert(nullptr != fsiTrgt);
366
367 return fsiTrgt;
368}
369
370//------------------------------------------------------------------------------
371
Zane Shelley35171d92020-12-03 13:31:13 -0600372// IMPORTANT:
Caleb Palmer626270a2022-02-21 11:05:08 -0600373// The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at
374// some point during the IPL. It is possible that this information is needed
375// before the sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600376uint32_t __getChipId(pdbg_target* i_trgt)
377{
378 uint32_t attr = 0;
379 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
380 return attr;
381}
382
Zane Shelley35171d92020-12-03 13:31:13 -0600383// IMPORTANT:
Caleb Palmer626270a2022-02-21 11:05:08 -0600384// The ATTR_EC attribute will be synced from Hostboot to the BMC at some
385// point during the IPL. It is possible that this information is needed
386// before the sync occurs, in which case the value will return 0.
Zane Shelley171a2e02020-11-13 13:56:13 -0600387uint8_t __getChipEc(pdbg_target* i_trgt)
388{
389 uint8_t attr = 0;
390 pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
391 return attr;
392}
393
394uint32_t __getChipIdEc(pdbg_target* i_trgt)
395{
Zane Shelley35171d92020-12-03 13:31:13 -0600396 auto chipId = __getChipId(i_trgt);
397 auto chipEc = __getChipEc(i_trgt);
398
399 if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt)))
400 {
401 // There is a special case where the model/level attributes have not
Caleb Palmer626270a2022-02-21 11:05:08 -0600402 // been initialized in the devtree. This is possible on the epoch
403 // IPL where an attention occurs before Hostboot is able to update
404 // the devtree information on the BMC. It may is still possible to
405 // get this information from chips with CFAM access (i.e. a
406 // processor) via the CFAM chip ID register.
Zane Shelley35171d92020-12-03 13:31:13 -0600407
408 uint32_t val = 0;
409 if (0 == getCfam(i_trgt, 0x100a, val))
410 {
411 chipId = ((val & 0x0F0FF000) >> 12);
412 chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20);
413 }
414 }
415
416 return ((chipId & 0xffff) << 16) | (chipEc & 0xff);
Zane Shelley171a2e02020-11-13 13:56:13 -0600417}
418
419void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
420 libhei::ChipType_t i_type)
421{
Caleb Palmer626270a2022-02-21 11:05:08 -0600422 // Trace each chip for debug. It is important to show the type just in
423 // case the model/EC does not exist. See note below.
Zane Shelley171a2e02020-11-13 13:56:13 -0600424 trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
425 getPath(i_trgt));
426
427 if (0 == i_type)
428 {
Caleb Palmer626270a2022-02-21 11:05:08 -0600429 // This is a special case. See the details in __getChipIdEC(). There
430 // is nothing more we can do with this chip since we don't know what
431 // it is. So ignore the chip for now.
Zane Shelley171a2e02020-11-13 13:56:13 -0600432 }
433 else
434 {
435 o_chips.emplace_back(i_trgt, i_type);
436 }
437}
438
439void getActiveChips(std::vector<libhei::Chip>& o_chips)
440{
441 o_chips.clear();
442
443 // Iterate each processor.
444 pdbg_target* procTrgt;
445 pdbg_for_each_class_target("proc", procTrgt)
446 {
447 // We cannot use the proc target to determine if the chip is active.
448 // There is some design limitation in pdbg that requires the proc
Caleb Palmer626270a2022-02-21 11:05:08 -0600449 // targets to always be active. Instead, we must get the associated
450 // pib target and check if it is active.
Zane Shelley171a2e02020-11-13 13:56:13 -0600451
452 // Active processors only.
453 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
454 continue;
455
456 // Add the processor to the list.
457 __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
458
459 // Iterate the connected OCMBs, if they exist.
460 pdbg_target* ocmbTrgt;
461 pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
462 {
463 // Active OCMBs only.
464 if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
465 continue;
466
467 // Add the OCMB to the list.
468 __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
469 }
470 }
471}
472
473//------------------------------------------------------------------------------
474
Zane Shelley3f363d42022-02-10 16:20:37 -0600475void getActiveProcessorChips(std::vector<pdbg_target*>& o_chips)
476{
477 o_chips.clear();
478
479 pdbg_target* procTrgt;
480 pdbg_for_each_class_target("proc", procTrgt)
481 {
482 // We cannot use the proc target to determine if the chip is active.
483 // There is some design limitation in pdbg that requires the proc
484 // targets to always be active. Instead, we must get the associated pib
485 // target and check if it is active.
486
487 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
488 continue;
489
490 o_chips.push_back(procTrgt);
491 }
492}
493
494//------------------------------------------------------------------------------
495
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600496pdbg_target* getPrimaryProcessor()
497{
Caleb Palmer626270a2022-02-21 11:05:08 -0600498 // TODO: For at least P10, the primary processor (the one connected
499 // directly
Zane Shelleyc18ba8f2021-12-01 16:29:20 -0600500 // to the BMC), will always be PROC 0. We will need to update this
501 // later if we ever support an alternate primary processor.
502 return getTrgt("/proc0");
503}
504
505//------------------------------------------------------------------------------
506
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600507bool queryHardwareAnalysisSupported()
508{
509 // Hardware analysis is only supported on P10 systems and up.
Zane Shelley5183af32020-12-07 14:49:03 -0600510 return (PDBG_PROC_P9 < pdbg_get_proc());
Zane Shelley7ae9c8c2020-12-02 20:10:31 -0600511}
512
513//------------------------------------------------------------------------------
514
Zane Shelley3a851082021-03-23 16:45:28 -0500515std::string getLocationCode(pdbg_target* trgt)
516{
517 if (nullptr == trgt)
518 {
519 // Either the path is wrong or the attribute doesn't exist.
520 return std::string{};
521 }
522
523#ifdef CONFIG_PHAL_API
524
525 ATTR_LOCATION_CODE_Type val;
526 if (DT_GET_PROP(ATTR_LOCATION_CODE, trgt, val))
527 {
528 // Get the immediate parent in the devtree path and try again.
529 return getLocationCode(pdbg_target_parent(nullptr, trgt));
530 }
531
532 // Attribute found.
533 return std::string{val};
534
535#else
536
537 return std::string{getPath(trgt)};
538
539#endif
540}
541
542//------------------------------------------------------------------------------
543
544std::string getPhysDevPath(pdbg_target* trgt)
545{
546 if (nullptr == trgt)
547 {
548 // Either the path is wrong or the attribute doesn't exist.
549 return std::string{};
550 }
551
552#ifdef CONFIG_PHAL_API
553
554 ATTR_PHYS_DEV_PATH_Type val;
555 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, trgt, val))
556 {
557 // Get the immediate parent in the devtree path and try again.
558 return getPhysDevPath(pdbg_target_parent(nullptr, trgt));
559 }
560
561 // Attribute found.
562 return std::string{val};
563
564#else
565
566 return std::string{getPath(trgt)};
567
568#endif
569}
570
571//------------------------------------------------------------------------------
572
Zane Shelleybf3326f2021-11-12 13:41:39 -0600573std::vector<uint8_t> getPhysBinPath(pdbg_target* target)
574{
575 std::vector<uint8_t> binPath;
576
577 if (nullptr != target)
578 {
579#ifdef CONFIG_PHAL_API
580
581 ATTR_PHYS_BIN_PATH_Type value;
582 if (DT_GET_PROP(ATTR_PHYS_BIN_PATH, target, value))
583 {
Caleb Palmer626270a2022-02-21 11:05:08 -0600584 // The attrirbute for this target does not exist. Get the
585 // immediate parent in the devtree path and try again. Note that
586 // if there is no parent target, nullptr will be returned and
587 // that will be checked above.
Zane Shelleybf3326f2021-11-12 13:41:39 -0600588 return getPhysBinPath(pdbg_target_parent(nullptr, target));
589 }
590
591 // Attribute was found. Copy the attribute array to the returned
592 // vector. Note that the reason we return the vector instead of just
593 // returning the array is because the array type and details only
594 // exists in this specific configuration.
595 binPath.insert(binPath.end(), value, value + sizeof(value));
596
597#endif
598 }
599
600 return binPath;
601}
602
603//------------------------------------------------------------------------------
604
Zane Shelleyf4bd5ff2020-11-05 22:26:04 -0600605} // namespace pdbg
606
607} // namespace util