pdbg utils for finding all active chips

Change-Id: I444c1062d28c10ecd47426c60ffe0604cc5eaac5
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/analyzer/analyzer_main.cpp b/analyzer/analyzer_main.cpp
index cf78149..30efd74 100644
--- a/analyzer/analyzer_main.cpp
+++ b/analyzer/analyzer_main.cpp
@@ -20,7 +20,7 @@
 
 // Forward references for externally defined functions.
 
-void initializeIsolator(const std::vector<libhei::Chip>& i_chips);
+void initializeIsolator(std::vector<libhei::Chip>& o_chips);
 
 //------------------------------------------------------------------------------
 
@@ -69,67 +69,6 @@
 
 //------------------------------------------------------------------------------
 
-// Returns the chip model/level of the given target.
-libhei::ChipType_t __getChipType(pdbg_target* i_trgt)
-{
-    libhei::ChipType_t type;
-
-    // START WORKAROUND
-    // TODO: Will need to grab the model/level from the target attributes when
-    //       they are available. For now, use ATTR_TYPE to determine which
-    //       currently supported value to use supported.
-    uint8_t attrType = util::pdbg::getTrgtType(i_trgt);
-    switch (attrType)
-    {
-        case 0x05: // PROC
-            type = 0x120DA049;
-            break;
-
-        case 0x4b: // OCMB_CHIP
-            type = 0x160D2000;
-            break;
-
-        default:
-            trace::err("Unsupported ATTR_TYPE value: 0x%02x", attrType);
-            assert(0);
-    }
-    // END WORKAROUND
-
-    return type;
-}
-
-//------------------------------------------------------------------------------
-
-// Gathers list of active chips to analyze.
-void __getActiveChips(std::vector<libhei::Chip>& o_chips)
-{
-    // Iterate each processor.
-    pdbg_target* procTrgt;
-    pdbg_for_each_class_target("proc", procTrgt)
-    {
-        // Active processors only.
-        if (PDBG_TARGET_ENABLED != pdbg_target_probe(procTrgt))
-            continue;
-
-        // Add the processor to the list.
-        o_chips.emplace_back(procTrgt, __getChipType(procTrgt));
-
-        // Iterate the connected OCMBs, if they exist.
-        pdbg_target* ocmbTrgt;
-        pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
-        {
-            // Active OCMBs only.
-            if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
-                continue;
-
-            // Add the OCMB to the list.
-            o_chips.emplace_back(ocmbTrgt, __getChipType(ocmbTrgt));
-        }
-    }
-}
-
-//------------------------------------------------------------------------------
-
 // Takes a signature list that will be filtered and sorted. The first entry in
 // the returned list will be the root cause. If the returned list is empty,
 // analysis failed.
@@ -237,12 +176,9 @@
 
     trace::inf(">>> enter analyzeHardware()");
 
-    // Get the active chips to be analyzed.
-    std::vector<libhei::Chip> chips;
-    __getActiveChips(chips);
-
-    // Initialize the isolator for all chips.
+    // Initialize the isolator and get all of the chips to be analyzed.
     trace::inf("Initializing the isolator...");
+    std::vector<libhei::Chip> chips;
     initializeIsolator(chips);
 
     // Isolate attentions.
diff --git a/analyzer/hei_user_interface.cpp b/analyzer/hei_user_interface.cpp
index 0f4a441..2422b38 100644
--- a/analyzer/hei_user_interface.cpp
+++ b/analyzer/hei_user_interface.cpp
@@ -43,10 +43,7 @@
     bool accessFailure = false;
 
     // The processor PIB target is required for SCOM access.
-    char path[16];
-    sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
-    pdbg_target* scomTrgt = pdbg_target_from_path(nullptr, path);
-    assert(nullptr != scomTrgt);
+    pdbg_target* scomTrgt = util::pdbg::getPibTrgt(i_procTrgt);
 
     switch (i_regType)
     {
diff --git a/analyzer/initialize_isolator.cpp b/analyzer/initialize_isolator.cpp
index 941b500..e75f5b3 100644
--- a/analyzer/initialize_isolator.cpp
+++ b/analyzer/initialize_isolator.cpp
@@ -105,8 +105,11 @@
 
 //------------------------------------------------------------------------------
 
-void initializeIsolator(const std::vector<libhei::Chip>& i_chips)
+void initializeIsolator(std::vector<libhei::Chip>& o_chips)
 {
+    // Get all of the active chips to be analyzed.
+    util::pdbg::getActiveChips(o_chips);
+
     // Find all of the existing chip data files.
     std::map<libhei::ChipType_t, fs::path> files;
     __getChipDataFiles(files);
@@ -114,25 +117,10 @@
     // Keep track of models/levels that have already been initialized.
     std::map<libhei::ChipType_t, unsigned int> initTypes;
 
-    for (const auto& chip : i_chips)
+    for (const auto& chip : o_chips)
     {
         auto chipType = chip.getType();
 
-        // Trace each chip for debug.
-        trace::inf("Chip found: type=0x%0" PRIx32 " chip=%s", chipType,
-                   util::pdbg::getPath(chip));
-
-        if (0 == chipType)
-        {
-            // This is a special case. It means the model/level attributes have
-            // not been initialized in the devtree. This is possible on the
-            // epoch IPL where an attention occurs before Hostboot is able to
-            // update the devtree information on the BMC.
-
-            // TODO: Consider logging a PEL. Just skip for now.
-            continue;
-        }
-
         // Mark this chip type as initialized (or will be if it hasn't been).
         auto ret = initTypes.emplace(chipType, 1);
         if (!ret.second)
diff --git a/util/pdbg.cpp b/util/pdbg.cpp
index 53c8020..0ca6574 100644
--- a/util/pdbg.cpp
+++ b/util/pdbg.cpp
@@ -1,4 +1,7 @@
+#include <assert.h>
+
 #include <util/pdbg.hpp>
+#include <util/trace.hpp>
 
 namespace util
 {
@@ -55,6 +58,100 @@
 
 //------------------------------------------------------------------------------
 
+pdbg_target* getPibTrgt(pdbg_target* i_procTrgt)
+{
+    // The input target must be a processor.
+    assert(0x05 == getTrgtType(i_procTrgt));
+
+    // Get the pib path.
+    char path[16];
+    sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
+
+    // Return the pib target.
+    pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path);
+    assert(nullptr != pibTrgt);
+
+    return pibTrgt;
+}
+
+//------------------------------------------------------------------------------
+
+uint32_t __getChipId(pdbg_target* i_trgt)
+{
+    uint32_t attr = 0;
+    pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
+    return attr;
+}
+
+uint8_t __getChipEc(pdbg_target* i_trgt)
+{
+    uint8_t attr = 0;
+    pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
+    return attr;
+}
+
+uint32_t __getChipIdEc(pdbg_target* i_trgt)
+{
+    return ((__getChipId(i_trgt) & 0xffff) << 16) | __getChipEc(i_trgt);
+}
+
+void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
+               libhei::ChipType_t i_type)
+{
+    // Trace each chip for debug. It is important to show the type just in case
+    // the model/EC does not exist. See note below.
+    trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
+               getPath(i_trgt));
+
+    if (0 == i_type)
+    {
+        // There is a special case where the model/level attributes have not
+        // been initialized in the devtree. This is possible on the epoch IPL
+        // where an attention occurs before Hostboot is able to update the
+        // devtree information on the BMC. For now, just ignore the chip.
+    }
+    else
+    {
+        o_chips.emplace_back(i_trgt, i_type);
+    }
+}
+
+void getActiveChips(std::vector<libhei::Chip>& o_chips)
+{
+    o_chips.clear();
+
+    // Iterate each processor.
+    pdbg_target* procTrgt;
+    pdbg_for_each_class_target("proc", procTrgt)
+    {
+        // We cannot use the proc target to determine if the chip is active.
+        // There is some design limitation in pdbg that requires the proc
+        // targets to always be active. Instead, we must get the associated pib
+        // target and check if it is active.
+
+        // Active processors only.
+        if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
+            continue;
+
+        // Add the processor to the list.
+        __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
+
+        // Iterate the connected OCMBs, if they exist.
+        pdbg_target* ocmbTrgt;
+        pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
+        {
+            // Active OCMBs only.
+            if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
+                continue;
+
+            // Add the OCMB to the list.
+            __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
 } // namespace pdbg
 
 } // namespace util
diff --git a/util/pdbg.hpp b/util/pdbg.hpp
index 58af138..33e4320 100644
--- a/util/pdbg.hpp
+++ b/util/pdbg.hpp
@@ -31,6 +31,19 @@
 /** @return The target type of the given chip. */
 uint8_t getTrgtType(const libhei::Chip& i_chip);
 
+/**
+ * @return The pib target associated with the given proc target.
+ * @note   Will assert the given target is a proc target.
+ * @note   Will assert the returned pib target it not nullptr.
+ */
+pdbg_target* getPibTrgt(pdbg_target* i_procTrgt);
+
+/**
+ * @brief Returns the list of all active chips in the system.
+ * @param o_chips The returned list of chips.
+ */
+void getActiveChips(std::vector<libhei::Chip>& o_chips);
+
 } // namespace pdbg
 
 } // namespace util