Odyssey PLL unlock analysis plugin
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: Ia53910eecdcdeb836bd836039a509f00121a67f7
diff --git a/analyzer/filter-root-cause.cpp b/analyzer/filter-root-cause.cpp
index d122a32..4efcff0 100644
--- a/analyzer/filter-root-cause.cpp
+++ b/analyzer/filter-root-cause.cpp
@@ -37,15 +37,35 @@
bool __findPllUnlock(const std::vector<libhei::Signature>& i_list,
libhei::Signature& o_rootCause)
{
+ using namespace util::pdbg;
+
// TODO: Consider returning all of them instead of one as root cause.
- auto itr = std::find_if(i_list.begin(), i_list.end(), [&](const auto& t) {
- return (libhei::hash<libhei::NodeId_t>("PLL_UNLOCK") == t.getId() &&
- (0 == t.getBit() || 1 == t.getBit()));
+
+ auto nodeId = libhei::hash<libhei::NodeId_t>("PLL_UNLOCK");
+
+ // First, look for any PLL unlock attentions reported by a processsor chip.
+ auto itr1 = std::find_if(i_list.begin(), i_list.end(), [&](const auto& t) {
+ return (nodeId == t.getId() &&
+ TYPE_PROC == getTrgtType(getTrgt(t.getChip())));
});
- if (i_list.end() != itr)
+ if (i_list.end() != itr1)
{
- o_rootCause = *itr;
+ o_rootCause = *itr1;
+ return true;
+ }
+
+ // Then, look for any PLL unlock attentions reported by an OCMB chip. This
+ // is specifically for Odyssey, which are the only OCMBs that would report
+ // PLL unlock attentions.
+ auto itr2 = std::find_if(i_list.begin(), i_list.end(), [&](const auto& t) {
+ return (nodeId == t.getId() &&
+ TYPE_OCMB == getTrgtType(getTrgt(t.getChip())));
+ });
+
+ if (i_list.end() != itr2)
+ {
+ o_rootCause = *itr2;
return true;
}
diff --git a/analyzer/meson.build b/analyzer/meson.build
index 7cee22e..1e6f342 100644
--- a/analyzer/meson.build
+++ b/analyzer/meson.build
@@ -11,6 +11,7 @@
)
plugins_src = files(
+ 'plugins/ody-plugins.cpp',
'plugins/p10-plugins.cpp',
'plugins/p10-tod-plugins.cpp',
)
diff --git a/analyzer/plugins/ody-plugins.cpp b/analyzer/plugins/ody-plugins.cpp
new file mode 100644
index 0000000..e71c7f5
--- /dev/null
+++ b/analyzer/plugins/ody-plugins.cpp
@@ -0,0 +1,83 @@
+
+#include <analyzer/plugins/plugin.hpp>
+#include <hei_util.hpp>
+#include <util/pdbg.hpp>
+#include <util/trace.hpp>
+
+namespace analyzer
+{
+
+namespace Ody
+{
+
+/**
+ * @brief Adds all chips in the OCMB PLL domain with active PLL unlock
+ * attentions to the callout list.
+ *
+ * An OCMB PLL domain is scoped to just the OCMBs under the same processor chip.
+ * If more than one OCMB within the PLL domain is reporting a PLL unlock
+ * attention, the clock source (the processor) is called out with high priority
+ * and all connected OCMBs are called out with low priority. Otherwise, single
+ * OCMB is called out high and the connected processor low.
+ */
+void pll_unlock(unsigned int, const libhei::Chip& i_ocmbChip,
+ ServiceData& io_servData)
+{
+ using namespace util::pdbg;
+
+ auto nodeId = libhei::hash<libhei::NodeId_t>("PLL_UNLOCK");
+
+ auto sigList = io_servData.getIsolationData().getSignatureList();
+
+ // The PLL list is initially the same size of the signature list.
+ std::vector<libhei::Signature> pllList{sigList.size()};
+
+ // Copy all signatures PLL signatures that match the node ID and parent
+ // processor chip.
+ auto procTrgt = getParentProcessor(getTrgt(i_ocmbChip));
+ auto itr = std::copy_if(sigList.begin(), sigList.end(), pllList.begin(),
+ [&nodeId, &procTrgt](const auto& s) {
+ return (nodeId == s.getId() &&
+ procTrgt == getParentProcessor(getTrgt(s.getChip())));
+ });
+
+ // Shrink the size of the PLL list if necessary.
+ pllList.resize(std::distance(pllList.begin(), itr));
+
+ // There should be at list one signature in the list.
+ if (0 == pllList.size())
+ {
+ throw std::logic_error("Expected at least one PLL unlock signature. "
+ "i_ocmbChip=" +
+ std::string{getPath(i_ocmbChip)});
+ }
+
+ // The hardware callouts will be all OCMBs with PLL unlock attentions and
+ // the connected processor chip. The callout priorities are dependent on the
+ // number of chips at attention.
+ if (1 == pllList.size())
+ {
+ // There is only one OCMB chip with a PLL unlock. So, the error is
+ // likely in the OCMB.
+ io_servData.calloutTarget(getTrgt(pllList.front().getChip()),
+ callout::Priority::HIGH, true);
+ io_servData.calloutTarget(procTrgt, callout::Priority::LOW, false);
+ }
+ else
+ {
+ // There are more than one OCMB chip with a PLL unlock. So, the error is
+ // likely the clock source, which is the processor.
+ io_servData.calloutTarget(procTrgt, callout::Priority::HIGH, true);
+ for (const auto& sig : pllList)
+ {
+ io_servData.calloutTarget(getTrgt(sig.getChip()),
+ callout::Priority::LOW, false);
+ }
+ }
+}
+
+} // namespace Ody
+
+PLUGIN_DEFINE_NS(ODYSSEY_10, Ody, pll_unlock);
+
+} // namespace analyzer