blob: 119c5ae92b5abf023a4d63fdccaa117592edbb87 [file] [log] [blame]
#include <isolator/hei_isolation_node.hpp>
#include <util/hei_bit_string.hpp>
namespace libhei
{
//------------------------------------------------------------------------------
bool IsolationNode::analyze(const Chip& i_chip, AttentionType_t i_attnType,
IsolationData& io_isoData) const
{
bool o_activeAttn = false; // Initially, assume no active attentions.
// Keep track of nodes that have been analyzed to avoid cyclic isolation.
pushIsolationStack();
// Capture default set of registers for this node.
captureRegisters(i_chip, io_isoData);
// Get the rule for this attention type.
auto rule_itr = iv_rules.find(i_attnType);
// It is possible that a rule does not exist. The likely scenario is that
// this node is intended to only gather FFDC for a specific bit in the
// parent node.
if (iv_rules.end() != rule_itr)
{
// Get the returned BitString for this rule.
const BitString* bs = rule_itr->second->getBitString(i_chip);
// Ensure this BitString is not longer than the maximum bit field.
HEI_ASSERT(bs->getBitLen() <= (1 << (sizeof(BitPosition_t) * 8)));
// Find all active bits for this rule.
for (BitPosition_t bit = 0; bit < bs->getBitLen(); bit++)
{
// Continue to the next bit if not active.
if (!bs->isBitSet(bit))
continue;
// At least one active bit was found.
o_activeAttn = true;
// Capture registers specific to this isolation bit.
captureRegisters(i_chip, io_isoData, bit);
// Determine if this attention originated from another register or
// if it is a leaf in the isolation tree.
auto child_itr = iv_children.find(bit);
if (iv_children.end() != child_itr)
{
// This bit was driven from an attention from another register.
// Continue down the isolation tree to look for more attentions.
bool attnFound =
child_itr->second->analyze(i_chip, i_attnType, io_isoData);
if (!attnFound)
{
// It is possible the child node is only intended for FFDC.
// See comment near the check for a valid rule above.
// Otherwise, it is possible something went wrong. If there
// should have been an active attention, it's possible there
// is a bug in the Chip Data File. Or, it is also possible
// some other piece of code is clearing the attention before
// this code is able to analyze it. Another possibility is
// that the hardware it not behaving as expected. Since we
// really don't know what happened, we should not assert.
// Instead, add this bit's signature to io_isoData. If there
// are no other active attentions, the user application
// could use this signature to help determine, and
// circumvent, the isolation problem.
io_isoData.addSignature(
Signature{i_chip, iv_id, iv_instance, bit, i_attnType});
}
}
else
{
// We have reached a leaf in the isolation tree. Add this bit's
// signature to io_isoData.
io_isoData.addSignature(
Signature{i_chip, iv_id, iv_instance, bit, i_attnType});
}
}
}
// Analysis is complete on this node. So remove it from cv_isolationStack.
popIsolationStack();
return o_activeAttn;
}
//------------------------------------------------------------------------------
void IsolationNode::addCaptureRegister(HardwareRegister::ConstPtr i_hwReg,
BitPosition_t i_bit)
{
HEI_ASSERT(i_hwReg); // should not be null
// Check the bit range.
if (MAX_BIT_POSITION != i_bit)
{
if (REG_TYPE_SCOM == iv_regType || REG_TYPE_ID_SCOM == iv_regType)
{
HEI_ASSERT(i_bit < 64);
}
else
{
HEI_ASSERT(false); // register type unsupported
}
}
// Add this capture register only if it does not already exist in the list.
auto itr = iv_capRegs.find(i_bit);
if (iv_capRegs.end() == itr ||
itr->second.end() ==
std::find(itr->second.begin(), itr->second.end(), i_hwReg))
{
iv_capRegs[i_bit].push_back(i_hwReg);
}
}
//------------------------------------------------------------------------------
void IsolationNode::addRule(AttentionType_t i_attnType,
Register::ConstPtr i_rule)
{
HEI_ASSERT(i_rule); // should not be null
auto ret = iv_rules.emplace(i_attnType, i_rule);
// If an entry already existed, it must point to the same object.
HEI_ASSERT(ret.second || (ret.first->second == i_rule));
}
//------------------------------------------------------------------------------
void IsolationNode::addChild(uint8_t i_bit, ConstPtr i_child)
{
HEI_ASSERT(i_child); // should not be null
auto ret = iv_children.emplace(i_bit, i_child);
// If an entry already existed, it must point to the same object.
HEI_ASSERT(ret.second || (ret.first->second == i_child));
}
//------------------------------------------------------------------------------
std::vector<const IsolationNode*> IsolationNode::cv_isolationStack{};
//------------------------------------------------------------------------------
void IsolationNode::pushIsolationStack() const
{
// Ensure this node does not already exist in cv_isolationStack.
auto itr =
std::find(cv_isolationStack.begin(), cv_isolationStack.end(), this);
HEI_ASSERT(cv_isolationStack.end() == itr);
// Push to node to the stack.
cv_isolationStack.push_back(this);
}
//------------------------------------------------------------------------------
void IsolationNode::captureRegisters(const Chip& i_chip,
IsolationData& io_isoData,
BitPosition_t i_bit) const
{
auto itr = iv_capRegs.find(i_bit);
if (iv_capRegs.end() != itr)
{
// Capture all registers for this node.
for (const auto& hwReg : itr->second)
{
// Read the register (adds BitString to register cache).
if (hwReg->read(i_chip))
{
// The register read failed.
// TODO: Would be nice to add SCOM errors to the log just in
// case
// traces are not available.
// TODO: This trace could be redundant with the user
// application,
// which will have more information on the actual chip
// that failed anyway. Leaving it commented out for now
// until the SCOM errors are added to the log.
// HEI_ERR("register read failed on chip type=0x%0" PRIx32
// "address=0x%0" PRIx64,
// i_chip.getType(), hwReg->getAddress());
}
else
{
// Add to the FFDC.
io_isoData.addRegister(i_chip, hwReg->getId(),
hwReg->getInstance(),
hwReg->getBitString(i_chip));
}
}
}
}
//------------------------------------------------------------------------------
} // end namespace libhei