1 2 #include <analyzer/plugins/plugin.hpp> 3 #include <hei_util.hpp> 4 #include <util/pdbg.hpp> 5 #include <util/trace.hpp> 6 7 namespace analyzer 8 { 9 10 namespace P10 11 { 12 13 /** 14 * @brief Adds all clocks/chips reporting PLL unlock attentions to the callout 15 * list. 16 * 17 * Processors are always called out at medium priority and never guarded. If 18 * more than one processor is reporting a PLL unlock attention on the same 19 * clock, the clock is called out with high priority. Otherwise, the clock 20 * callout priority is medium. 21 */ 22 void pll_unlock(unsigned int i_instance, const libhei::Chip&, 23 ServiceData& io_servData) 24 { 25 auto nodeId = libhei::hash<libhei::NodeId_t>("PLL_UNLOCK"); 26 27 auto sigList = io_servData.getIsolationData().getSignatureList(); 28 29 // The PLL list is initially the same size of the signature list. 30 std::vector<libhei::Signature> pllList{sigList.size()}; 31 32 // Copy all signatures that match the node ID and bit position. Note that 33 // in this case the bit position is the same as the plugin instance. 34 auto itr = std::copy_if(sigList.begin(), sigList.end(), pllList.begin(), 35 [&nodeId, &i_instance](const auto& s) { 36 return (nodeId == s.getId() && 37 i_instance == s.getBit()); 38 }); 39 40 // Shrink the size of the PLL list if necessary. 41 pllList.resize(std::distance(pllList.begin(), itr)); 42 43 // The clock callout priority is dependent on the number of chips with PLL 44 // unlock attentions. 45 auto clockPriority = 46 (1 < pllList.size()) ? callout::Priority::HIGH : callout::Priority::MED; 47 48 // Callout the clock. 49 auto clockCallout = (0 == i_instance) ? callout::ClockType::OSC_REF_CLOCK_0 50 : callout::ClockType::OSC_REF_CLOCK_1; 51 io_servData.calloutClock(clockCallout, clockPriority, true); 52 53 // Callout the processors connected to this clock that are reporting PLL 54 // unlock attentions. Always a medium callout and no guarding. 55 for (const auto& sig : pllList) 56 { 57 io_servData.calloutTarget(util::pdbg::getTrgt(sig.getChip()), 58 callout::Priority::MED, false); 59 } 60 } 61 62 void lpc_timeout_callout(const libhei::Chip& i_chip, ServiceData& io_servData) 63 { 64 auto target = util::pdbg::getTrgt(i_chip); 65 auto path = util::pdbg::getPath(target); 66 67 // Callout the PNOR. 68 io_servData.calloutPart(callout::PartType::PNOR, callout::Priority::MED); 69 70 // Callout the associated clock, no guard. 71 auto chipPos = util::pdbg::getChipPos(target); 72 if (0 == chipPos) 73 { 74 // Clock 0 is hardwired to proc 0. 75 io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_0, 76 callout::Priority::MED, false); 77 } 78 else if (1 == chipPos) 79 { 80 // Clock 1 is hardwired to proc 1. 81 io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_1, 82 callout::Priority::MED, false); 83 } 84 else 85 { 86 trace::err("LPC timeout on unexpected processor: %s", path); 87 } 88 89 // Callout the processor, no guard. 90 io_servData.calloutTarget(target, callout::Priority::MED, false); 91 } 92 93 /** 94 * @brief Queries for an LPC timeout. If present, will callout all appropriate 95 * hardware. 96 */ 97 void lpc_timeout(unsigned int, const libhei::Chip& i_chip, 98 ServiceData& io_servData) 99 { 100 auto target = util::pdbg::getTrgt(i_chip); 101 auto path = util::pdbg::getPath(target); 102 103 if (util::pdbg::queryLpcTimeout(target)) 104 { 105 trace::inf("LPC timeout detected on %s", path); 106 107 lpc_timeout_callout(i_chip, io_servData); 108 } 109 else 110 { 111 trace::inf("No LPC timeout detected on %s", path); 112 113 io_servData.calloutProcedure(callout::Procedure::NEXTLVL, 114 callout::Priority::HIGH); 115 } 116 } 117 118 /** 119 * @brief If Hostboot detects an LPC timeout, it will manually trigger a 120 * checkstop attention. We will have to bypass checking for an LPC 121 * timeout via the HWP because it will not find the timeout. Instead, 122 * simply make the callout when Hostboot triggers the attention. 123 */ 124 void lpc_timeout_workaround(unsigned int, const libhei::Chip& i_chip, 125 ServiceData& io_servData) 126 { 127 trace::inf("Host detected LPC timeout %s", util::pdbg::getPath(i_chip)); 128 129 lpc_timeout_callout(i_chip, io_servData); 130 } 131 132 /** 133 * @brief Calls out all DIMMs attached to an OCMB. 134 */ 135 void callout_attached_dimms(unsigned int i_instance, const libhei::Chip& i_chip, 136 ServiceData& io_servData) 137 { 138 // Get the OMI target for this instance 139 auto procTarget = util::pdbg::getTrgt(i_chip); 140 auto omiTarget = 141 util::pdbg::getChipUnit(procTarget, util::pdbg::TYPE_OMI, i_instance); 142 143 if (nullptr != omiTarget) 144 { 145 // Get the connected OCMB from the OMI 146 auto ocmbTarget = util::pdbg::getConnectedTarget( 147 omiTarget, callout::BusType::OMI_BUS); 148 149 // Loop through all DIMMs connected to the OCMB 150 pdbg_target* dimmTarget = nullptr; 151 pdbg_for_each_target("dimm", ocmbTarget, dimmTarget) 152 { 153 if (nullptr != dimmTarget) 154 { 155 // Call out the DIMM, medium priority and guard 156 io_servData.calloutTarget(dimmTarget, callout::Priority::MED, 157 true); 158 } 159 } 160 } 161 } 162 163 } // namespace P10 164 165 PLUGIN_DEFINE_NS(P10_10, P10, pll_unlock); 166 PLUGIN_DEFINE_NS(P10_20, P10, pll_unlock); 167 168 PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout); 169 PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout); 170 171 PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout_workaround); 172 PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout_workaround); 173 174 PLUGIN_DEFINE_NS(P10_10, P10, callout_attached_dimms); 175 PLUGIN_DEFINE_NS(P10_20, P10, callout_attached_dimms); 176 177 } // namespace analyzer 178