#include #include #include #include namespace analyzer { namespace P10 { /** * @brief Adds all clocks/chips reporting PLL unlock attentions to the callout * list. * * Processors are always called out at medium priority and never guarded. If * more than one processor is reporting a PLL unlock attention on the same * clock, the clock is called out with high priority. Otherwise, the clock * callout priority is medium. */ void pll_unlock(unsigned int i_instance, const libhei::Chip&, ServiceData& io_servData) { auto nodeId = libhei::hash("PLL_UNLOCK"); auto sigList = io_servData.getIsolationData().getSignatureList(); // The PLL list is initially the same size of the signature list. std::vector pllList{sigList.size()}; // Copy all signatures that match the node ID and bit position. Note that // in this case the bit position is the same as the plugin instance. auto itr = std::copy_if(sigList.begin(), sigList.end(), pllList.begin(), [&nodeId, &i_instance](const auto& s) { return (nodeId == s.getId() && i_instance == s.getBit()); }); // Shrink the size of the PLL list if necessary. pllList.resize(std::distance(pllList.begin(), itr)); // The clock callout priority is dependent on the number of chips with PLL // unlock attentions. auto clockPriority = (1 < pllList.size()) ? callout::Priority::HIGH : callout::Priority::MED; // Callout the clock. auto clockCallout = (0 == i_instance) ? callout::ClockType::OSC_REF_CLOCK_0 : callout::ClockType::OSC_REF_CLOCK_1; io_servData.calloutClock(clockCallout, clockPriority, true); // Callout the processors connected to this clock that are reporting PLL // unlock attentions. Always a medium callout and no guarding. for (const auto& sig : pllList) { io_servData.calloutTarget(util::pdbg::getTrgt(sig.getChip()), callout::Priority::MED, false); } } void lpc_timeout_callout(const libhei::Chip& i_chip, ServiceData& io_servData) { auto target = util::pdbg::getTrgt(i_chip); auto path = util::pdbg::getPath(target); // Callout the PNOR. io_servData.calloutPart(callout::PartType::PNOR, callout::Priority::MED); // Callout the associated clock, no guard. auto chipPos = util::pdbg::getChipPos(target); if (0 == chipPos) { // Clock 0 is hardwired to proc 0. io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_0, callout::Priority::MED, false); } else if (1 == chipPos) { // Clock 1 is hardwired to proc 1. io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_1, callout::Priority::MED, false); } else { trace::err("LPC timeout on unexpected processor: %s", path); } // Callout the processor, no guard. io_servData.calloutTarget(target, callout::Priority::MED, false); } /** * @brief Queries for an LPC timeout. If present, will callout all appropriate * hardware. */ void lpc_timeout(unsigned int, const libhei::Chip& i_chip, ServiceData& io_servData) { auto target = util::pdbg::getTrgt(i_chip); auto path = util::pdbg::getPath(target); if (util::pdbg::queryLpcTimeout(target)) { trace::inf("LPC timeout detected on %s", path); lpc_timeout_callout(i_chip, io_servData); } else { trace::inf("No LPC timeout detected on %s", path); io_servData.calloutProcedure(callout::Procedure::NEXTLVL, callout::Priority::HIGH); } } /** * @brief If Hostboot detects an LPC timeout, it will manually trigger a * checkstop attention. We will have to bypass checking for an LPC * timeout via the HWP because it will not find the timeout. Instead, * simply make the callout when Hostboot triggers the attention. */ void lpc_timeout_workaround(unsigned int, const libhei::Chip& i_chip, ServiceData& io_servData) { trace::inf("Host detected LPC timeout %s", util::pdbg::getPath(i_chip)); lpc_timeout_callout(i_chip, io_servData); } /** * @brief Calls out all DIMMs attached to an OCMB. */ void callout_attached_dimms(unsigned int i_instance, const libhei::Chip& i_chip, ServiceData& io_servData) { // Get the OMI target for this instance auto procTarget = util::pdbg::getTrgt(i_chip); auto omiTarget = util::pdbg::getChipUnit(procTarget, util::pdbg::TYPE_OMI, i_instance); if (nullptr != omiTarget) { // Get the connected OCMB from the OMI auto ocmbTarget = util::pdbg::getConnectedTarget( omiTarget, callout::BusType::OMI_BUS); // Loop through all DIMMs connected to the OCMB pdbg_target* dimmTarget = nullptr; pdbg_for_each_target("dimm", ocmbTarget, dimmTarget) { if (nullptr != dimmTarget) { // Call out the DIMM, medium priority and guard io_servData.calloutTarget(dimmTarget, callout::Priority::MED, true); } } } } } // namespace P10 PLUGIN_DEFINE_NS(P10_10, P10, pll_unlock); PLUGIN_DEFINE_NS(P10_20, P10, pll_unlock); PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout); PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout); PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout_workaround); PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout_workaround); PLUGIN_DEFINE_NS(P10_10, P10, callout_attached_dimms); PLUGIN_DEFINE_NS(P10_20, P10, callout_attached_dimms); } // namespace analyzer