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 Ody
11 {
12 
13 /**
14  * @brief Adds all chips in the OCMB PLL domain with active PLL unlock
15  *        attentions to the callout list.
16  *
17  * An OCMB PLL domain is scoped to just the OCMBs under the same processor chip.
18  * If more than one OCMB within the PLL domain is reporting a PLL unlock
19  * attention, the clock source (the processor) is called out with high priority
20  * and all connected OCMBs are called out with low priority. Otherwise, single
21  * OCMB is called out high and the connected processor low.
22  */
pll_unlock(unsigned int,const libhei::Chip & i_ocmbChip,ServiceData & io_servData)23 void pll_unlock(unsigned int, const libhei::Chip& i_ocmbChip,
24                 ServiceData& io_servData)
25 {
26     using namespace util::pdbg;
27 
28     auto nodeId = libhei::hash<libhei::NodeId_t>("PLL_UNLOCK");
29 
30     auto sigList = io_servData.getIsolationData().getSignatureList();
31 
32     // The PLL list is initially the same size of the signature list.
33     std::vector<libhei::Signature> pllList{sigList.size()};
34 
35     // Copy all signatures PLL signatures that match the node ID and parent
36     // processor chip.
37     auto procTrgt = getParentProcessor(getTrgt(i_ocmbChip));
38     auto itr = std::copy_if(
39         sigList.begin(), sigList.end(), pllList.begin(),
40         [&nodeId, &procTrgt](const auto& s) {
41             return (nodeId == s.getId() &&
42                     procTrgt == getParentProcessor(getTrgt(s.getChip())));
43         });
44 
45     // Shrink the size of the PLL list if necessary.
46     pllList.resize(std::distance(pllList.begin(), itr));
47 
48     // There should be at list one signature in the list.
49     if (0 == pllList.size())
50     {
51         throw std::logic_error("Expected at least one PLL unlock signature. "
52                                "i_ocmbChip=" +
53                                std::string{getPath(i_ocmbChip)});
54     }
55 
56     // The hardware callouts will be all OCMBs with PLL unlock attentions and
57     // the connected processor chip. The callout priorities are dependent on the
58     // number of chips at attention.
59     if (1 == pllList.size())
60     {
61         // There is only one OCMB chip with a PLL unlock. So, the error is
62         // likely in the OCMB.
63         io_servData.calloutTarget(getTrgt(pllList.front().getChip()),
64                                   callout::Priority::HIGH, true);
65         io_servData.calloutTarget(procTrgt, callout::Priority::LOW, false);
66     }
67     else
68     {
69         // There are more than one OCMB chip with a PLL unlock. So, the error is
70         // likely the clock source, which is the processor.
71         io_servData.calloutTarget(procTrgt, callout::Priority::HIGH, true);
72         for (const auto& sig : pllList)
73         {
74             io_servData.calloutTarget(getTrgt(sig.getChip()),
75                                       callout::Priority::LOW, false);
76         }
77     }
78 }
79 
80 } // namespace Ody
81 
82 PLUGIN_DEFINE_NS(ODYSSEY_10, Ody, pll_unlock);
83 
84 } // namespace analyzer
85