ConnectedCalloutResolution support
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: Id1b215d70ca98ae18528f91162ff4d99de9e9ce8
diff --git a/analyzer/callout.hpp b/analyzer/callout.hpp
index 51cf4ed..b49f97b 100644
--- a/analyzer/callout.hpp
+++ b/analyzer/callout.hpp
@@ -110,6 +110,44 @@
inline const Procedure Procedure::NEXTLVL{"NEXTLVL"};
+/** @brief Container class for bus callout service actions. */
+class BusType
+{
+ public:
+ /** SMP bus (fabric A or X bus). */
+ static const BusType SMP_BUS;
+
+ /** OMI bus (memory bus). */
+ static const BusType OMI_BUS;
+
+ private:
+ /**
+ * @brief Constructor from components.
+ * @param i_string The string representation of the procedure used for
+ * callouts.
+ */
+ explicit BusType(const std::string& i_string) : iv_string(i_string) {}
+
+ private:
+ /** The string representation of the procedure used for callouts. */
+ const std::string iv_string;
+
+ public:
+ bool operator==(const BusType& r) const
+ {
+ return this->iv_string == r.iv_string;
+ }
+
+ /** iv_string accessor */
+ std::string getString() const
+ {
+ return iv_string;
+ }
+};
+
+inline const BusType BusType::SMP_BUS{"SMP_BUS"};
+inline const BusType BusType::OMI_BUS{"OMI_BUS"};
+
/** @brief Container class for clock callout service actions. */
class ClockType
{
diff --git a/analyzer/ras-data/data/ras-data-explorer-11.json b/analyzer/ras-data/data/ras-data-explorer-11.json
index 8c835b4..37a216e 100644
--- a/analyzer/ras-data/data/ras-data-explorer-11.json
+++ b/analyzer/ras-data/data/ras-data-explorer-11.json
@@ -7,7 +7,7 @@
},
"buses" : {
"omi_bus": {
- "type": "parent"
+ "type": "OMI_BUS"
}
},
"actions" : {
diff --git a/analyzer/ras-data/data/ras-data-explorer-20.json b/analyzer/ras-data/data/ras-data-explorer-20.json
index 2bee510..1d99c6a 100644
--- a/analyzer/ras-data/data/ras-data-explorer-20.json
+++ b/analyzer/ras-data/data/ras-data-explorer-20.json
@@ -7,7 +7,7 @@
},
"buses" : {
"omi_bus": {
- "type": "parent"
+ "type": "OMI_BUS"
}
},
"actions" : {
diff --git a/analyzer/ras-data/ras-data-definition.md b/analyzer/ras-data/ras-data-definition.md
index 2538230..b7846d7 100644
--- a/analyzer/ras-data/ras-data-definition.md
+++ b/analyzer/ras-data/ras-data-definition.md
@@ -58,7 +58,7 @@
| Keyword | Description |
|---------|--------------------------------------------------------------------|
-| type | The bus connection type. Values (string): `peer`, `parent`, `child`|
+| type | The bus connection type. Values (string): `SMP_BUS` and `OMI_BUS` |
| unit | Optional. The `<unit_name>` of the bus endpoint on this chip. |
## 5) `actions` keyword (required)
diff --git a/analyzer/ras-data/ras-data-parser.cpp b/analyzer/ras-data/ras-data-parser.cpp
index d59c289..ea59c07 100644
--- a/analyzer/ras-data/ras-data-parser.cpp
+++ b/analyzer/ras-data/ras-data-parser.cpp
@@ -118,6 +118,33 @@
//------------------------------------------------------------------------------
+std::tuple<callout::BusType, std::string>
+ RasDataParser::parseBus(const nlohmann::json& i_data,
+ const std::string& i_name)
+{
+ auto bus = i_data.at("buses").at(i_name);
+
+ // clang-format off
+ static const std::map<std::string, callout::BusType> m =
+ {
+ {"SMP_BUS", callout::BusType::SMP_BUS},
+ {"OMI_BUS", callout::BusType::OMI_BUS},
+ };
+ // clang-format on
+
+ auto busType = m.at(bus.at("type").get<std::string>());
+
+ std::string unitPath{}; // default empty if unit does not exist
+ if (bus.contains("unit"))
+ {
+ unitPath = bus.at("unit").get<std::string>();
+ }
+
+ return std::make_tuple(busType, unitPath);
+}
+
+//------------------------------------------------------------------------------
+
std::shared_ptr<Resolution>
RasDataParser::parseAction(const nlohmann::json& i_data,
const std::string& i_action)
@@ -168,9 +195,11 @@
auto priority = a.at("priority").get<std::string>();
auto guard = a.at("guard").get<bool>();
- // TODO
- trace::inf("callout_connected: name=%s priority=%s guard=%c",
- name.c_str(), priority.c_str(), guard ? 'T' : 'F');
+ auto busData = parseBus(i_data, name);
+
+ o_list->push(std::make_shared<ConnectedCalloutResolution>(
+ std::get<0>(busData), std::get<1>(busData),
+ getPriority(priority), guard));
}
else if ("callout_bus" == type)
{
diff --git a/analyzer/ras-data/ras-data-parser.hpp b/analyzer/ras-data/ras-data-parser.hpp
index fe5e4a1..60d9ab7 100644
--- a/analyzer/ras-data/ras-data-parser.hpp
+++ b/analyzer/ras-data/ras-data-parser.hpp
@@ -54,6 +54,17 @@
const libhei::Signature& i_signature);
/**
+ * @brief Parses a bus object in the given data file and returns the bus
+ * type and unit path.
+ * @param i_data The parsed RAS data file associated with the signature's
+ * chip type.
+ * @param i_name The name of the target bus.
+ * @return A tuple containing the bus type and unit path.
+ */
+ std::tuple<callout::BusType, std::string>
+ parseBus(const nlohmann::json& i_data, const std::string& i_name);
+
+ /**
* @brief Parses an action in the given data file and returns the
* corresponding resolution.
* @param i_data The parsed RAS data file associated with the signature's
diff --git a/analyzer/ras-data/schema/ras-data-schema-v01.json b/analyzer/ras-data/schema/ras-data-schema-v01.json
index 9ec7150..d675631 100644
--- a/analyzer/ras-data/schema/ras-data-schema-v01.json
+++ b/analyzer/ras-data/schema/ras-data-schema-v01.json
@@ -48,7 +48,7 @@
"properties": {
"type": {
"type": "string",
- "enum": [ "peer", "parent", "child" ]
+ "enum": [ "SMP_BUS", "OMI_BUS" ]
},
"unit": {
"type": "string",
diff --git a/analyzer/resolution.cpp b/analyzer/resolution.cpp
index fb451aa..d6cd174 100644
--- a/analyzer/resolution.cpp
+++ b/analyzer/resolution.cpp
@@ -44,6 +44,76 @@
//------------------------------------------------------------------------------
+// Helper function to get the connected target on the other side of the
+// given bus.
+pdbg_target* __getConnectedTarget(pdbg_target* i_rxTarget,
+ const callout::BusType& i_busType)
+{
+ assert(nullptr != i_rxTarget);
+
+ pdbg_target* txTarget = nullptr;
+
+ auto rxType = util::pdbg::getTrgtType(i_rxTarget);
+ std::string rxPath = util::pdbg::getPath(i_rxTarget);
+
+ if (callout::BusType::SMP_BUS == i_busType &&
+ util::pdbg::TYPE_IOLINK == rxType)
+ {
+ // TODO: Will need to reference some sort of data that can tell us how
+ // the processors are connected in the system. For now, return the
+ // RX target to avoid returning a nullptr.
+ trace::inf("No support to get peer target on SMP bus");
+ txTarget = i_rxTarget;
+ }
+ else if (callout::BusType::OMI_BUS == i_busType &&
+ util::pdbg::TYPE_OMI == rxType)
+ {
+ // This is a bit clunky. The pdbg APIs only give us the ability to
+ // iterate over the children instead of just returning a list. So we'll
+ // push all the children to a list and go from there.
+ std::vector<pdbg_target*> childList;
+
+ pdbg_target* childTarget = nullptr;
+ pdbg_for_each_target("ocmb", i_rxTarget, childTarget)
+ {
+ if (nullptr != childTarget)
+ {
+ childList.push_back(childTarget);
+ }
+ }
+
+ // We know there should only be one OCMB per OMI.
+ if (1 != childList.size())
+ {
+ throw std::logic_error("Invalid child list size for " + rxPath);
+ }
+
+ // Get the connected target.
+ txTarget = childList.front();
+ }
+ else if (callout::BusType::OMI_BUS == i_busType &&
+ util::pdbg::TYPE_OCMB == rxType)
+ {
+ txTarget = pdbg_target_parent("omi", i_rxTarget);
+ if (nullptr == txTarget)
+ {
+ throw std::logic_error("No parent OMI found for " + rxPath);
+ }
+ }
+ else
+ {
+ // This would be a code bug.
+ throw std::logic_error("Unsupported config: i_rxTarget=" + rxPath +
+ " i_busType=" + i_busType.getString());
+ }
+
+ assert(nullptr != txTarget); // just in case we missed something above
+
+ return txTarget;
+}
+
+//------------------------------------------------------------------------------
+
void HardwareCalloutResolution::resolve(ServiceData& io_sd) const
{
// Get the target for the hardware callout.
@@ -73,6 +143,39 @@
//------------------------------------------------------------------------------
+void ConnectedCalloutResolution::resolve(ServiceData& io_sd) const
+{
+ // Get the chip target from the root cause signature.
+ auto chipTarget = __getRootCauseChipTarget(io_sd);
+
+ // Get the endpoint target for the receiving side of the bus.
+ auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
+
+ // Get the endpoint target for the transfer side of the bus.
+ auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
+
+ // Callout the TX endpoint.
+ nlohmann::json txCallout;
+ txCallout["LocationCode"] = util::pdbg::getLocationCode(txTarget);
+ txCallout["Priority"] = iv_priority.getUserDataString();
+ io_sd.addCallout(txCallout);
+
+ // Guard the TX endpoint.
+ Guard txGuard =
+ io_sd.addGuard(util::pdbg::getPhysDevPath(txTarget), iv_guard);
+
+ // Add the callout FFDC to the service data.
+ nlohmann::json ffdc;
+ ffdc["Callout Type"] = "Connected Callout";
+ ffdc["Bus Type"] = iv_busType.getString();
+ ffdc["Target"] = util::pdbg::getPhysDevPath(txTarget);
+ ffdc["Priority"] = iv_priority.getRegistryString();
+ ffdc["Guard Type"] = txGuard.getString();
+ io_sd.addCalloutFFDC(ffdc);
+}
+
+//------------------------------------------------------------------------------
+
void ClockCalloutResolution::resolve(ServiceData& io_sd) const
{
// Add the callout to the service data.
diff --git a/analyzer/resolution.hpp b/analyzer/resolution.hpp
index 7c20647..aee3851 100644
--- a/analyzer/resolution.hpp
+++ b/analyzer/resolution.hpp
@@ -57,6 +57,46 @@
void resolve(ServiceData& io_sd) const override;
};
+/** @brief Resolution to callout a connected chip/target. */
+class ConnectedCalloutResolution : public Resolution
+{
+ public:
+ /**
+ * @brief Constructor from components.
+ * @param i_busType The bus type.
+ * @param i_unitPath The path of the chip unit that is connected to the
+ * other chip. An empty string refers to the chip itself,
+ * which generally means this chip is a child of another.
+ * @param i_priority The callout priority.
+ * @param i_guard The guard type for this callout.
+ */
+ ConnectedCalloutResolution(const callout::BusType& i_busType,
+ const std::string& i_unitPath,
+ const callout::Priority& i_priority,
+ bool i_guard) :
+ iv_busType(i_busType),
+ iv_unitPath(i_unitPath), iv_priority(i_priority), iv_guard(i_guard)
+ {}
+
+ private:
+ /** The bus type. */
+ const callout::BusType iv_busType;
+
+ /** The devtree path the chip unit that is connected to the other chip. An
+ * empty string refers to the chip itself, which generally means this chip
+ * is a child of the other chip. */
+ const std::string iv_unitPath;
+
+ /** The callout priority. */
+ const callout::Priority iv_priority;
+
+ /** True, if guard is required. False, otherwise. */
+ const bool iv_guard;
+
+ public:
+ void resolve(ServiceData& io_sd) const override;
+};
+
/** @brief Resolves a clock callout service event. */
class ClockCalloutResolution : public Resolution
{