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 */
pll_unlock(unsigned int i_instance,const libhei::Chip &,ServiceData & io_servData)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
lpc_timeout_callout(const libhei::Chip & i_chip,ServiceData & io_servData)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 */
lpc_timeout(unsigned int,const libhei::Chip & i_chip,ServiceData & io_servData)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 */
lpc_timeout_workaround(unsigned int,const libhei::Chip & i_chip,ServiceData & io_servData)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 */
callout_attached_dimms(unsigned int i_instance,const libhei::Chip & i_chip,ServiceData & io_servData)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