1 #include <analyzer/service_data.hpp>
2 
3 namespace analyzer
4 {
5 
6 //------------------------------------------------------------------------------
7 
8 void ServiceData::calloutTarget(pdbg_target* i_target,
9                                 const callout::Priority& i_priority,
10                                 bool i_guard)
11 {
12     // Add the target to the callout list.
13     addTargetCallout(i_target, i_priority, i_guard);
14 
15     // Add the callout FFDC.
16     nlohmann::json ffdc;
17     ffdc["Callout Type"] = "Hardware Callout";
18     ffdc["Target"]       = util::pdbg::getPhysDevPath(i_target);
19     ffdc["Priority"]     = i_priority.getRegistryString();
20     ffdc["Guard"]        = i_guard;
21     addCalloutFFDC(ffdc);
22 }
23 
24 //------------------------------------------------------------------------------
25 
26 void ServiceData::calloutConnected(pdbg_target* i_rxTarget,
27                                    const callout::BusType& i_busType,
28                                    const callout::Priority& i_priority,
29                                    bool i_guard)
30 {
31     // Get the endpoint target for the transfer side of the bus.
32     auto txTarget = util::pdbg::getConnectedTarget(i_rxTarget, i_busType);
33 
34     // Callout the TX endpoint.
35     addTargetCallout(txTarget, i_priority, i_guard);
36 
37     // Add the callout FFDC.
38     nlohmann::json ffdc;
39     ffdc["Callout Type"] = "Connected Callout";
40     ffdc["Bus Type"]     = i_busType.getString();
41     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(i_rxTarget);
42     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
43     ffdc["Priority"]     = i_priority.getRegistryString();
44     ffdc["Guard"]        = i_guard;
45     addCalloutFFDC(ffdc);
46 }
47 
48 //------------------------------------------------------------------------------
49 
50 void ServiceData::calloutBus(pdbg_target* i_rxTarget,
51                              const callout::BusType& i_busType,
52                              const callout::Priority& i_priority, bool i_guard)
53 {
54     // Get the endpoint target for the transfer side of the bus.
55     auto txTarget = util::pdbg::getConnectedTarget(i_rxTarget, i_busType);
56 
57     // Callout the RX endpoint.
58     addTargetCallout(i_rxTarget, i_priority, i_guard);
59 
60     // Callout the TX endpoint.
61     addTargetCallout(txTarget, i_priority, i_guard);
62 
63     // Callout everything else in between.
64     // TODO: For P10 (OMI bus and XBUS), the callout is simply the backplane.
65     addBackplaneCallout(i_priority);
66 
67     // Add the callout FFDC.
68     nlohmann::json ffdc;
69     ffdc["Callout Type"] = "Bus Callout";
70     ffdc["Bus Type"]     = i_busType.getString();
71     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(i_rxTarget);
72     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
73     ffdc["Priority"]     = i_priority.getRegistryString();
74     ffdc["Guard"]        = i_guard;
75     addCalloutFFDC(ffdc);
76 }
77 
78 //------------------------------------------------------------------------------
79 
80 void ServiceData::calloutClock(const callout::ClockType& i_clockType,
81                                const callout::Priority& i_priority, bool)
82 {
83     // Callout the clock target.
84     // TODO: For P10, the callout is simply the backplane. Also, there are no
85     //       clock targets in the device tree. So at the moment there is no
86     //       guard support for clock targets.
87     addBackplaneCallout(i_priority);
88 
89     // Add the callout FFDC.
90     // TODO: Add the target and guard type if guard is ever supported.
91     nlohmann::json ffdc;
92     ffdc["Callout Type"] = "Clock Callout";
93     ffdc["Clock Type"]   = i_clockType.getString();
94     ffdc["Priority"]     = i_priority.getRegistryString();
95     addCalloutFFDC(ffdc);
96 }
97 
98 //------------------------------------------------------------------------------
99 
100 void ServiceData::calloutProcedure(const callout::Procedure& i_procedure,
101                                    const callout::Priority& i_priority)
102 {
103     // Add the actual callout to the service data.
104     nlohmann::json callout;
105     callout["Procedure"] = i_procedure.getString();
106     callout["Priority"]  = i_priority.getUserDataString();
107     addCallout(callout);
108 
109     // Add the callout FFDC.
110     nlohmann::json ffdc;
111     ffdc["Callout Type"] = "Procedure Callout";
112     ffdc["Procedure"]    = i_procedure.getString();
113     ffdc["Priority"]     = i_priority.getRegistryString();
114     addCalloutFFDC(ffdc);
115 }
116 
117 //------------------------------------------------------------------------------
118 
119 void ServiceData::addCallout(const nlohmann::json& i_callout)
120 {
121     // The new callout is either a hardware callout with a location code or a
122     // procedure callout.
123 
124     std::string type{};
125     if (i_callout.contains("LocationCode"))
126     {
127         type = "LocationCode";
128     }
129     else if (i_callout.contains("Procedure"))
130     {
131         type = "Procedure";
132     }
133     else
134     {
135         throw std::logic_error("Unsupported callout: " + i_callout.dump());
136     }
137 
138     // A map to determine the priority order. All of the medium priorities,
139     // including the medium group priorities, are all the same level.
140     static const std::map<std::string, unsigned int> m = {
141         {"H", 3}, {"M", 2}, {"A", 2}, {"B", 2}, {"C", 2}, {"L", 1},
142     };
143 
144     bool addCallout = true;
145 
146     for (auto& c : iv_calloutList)
147     {
148         if (c.contains(type) && (c.at(type) == i_callout.at(type)))
149         {
150             // The new callout already exists. Don't add a new callout.
151             addCallout = false;
152 
153             if (m.at(c.at("Priority")) < m.at(i_callout.at("Priority")))
154             {
155                 // The new callout has a higher priority, update it.
156                 c["Priority"] = i_callout.at("Priority");
157             }
158         }
159     }
160 
161     if (addCallout)
162     {
163         iv_calloutList.push_back(i_callout);
164     }
165 }
166 
167 //------------------------------------------------------------------------------
168 
169 void ServiceData::addTargetCallout(pdbg_target* i_target,
170                                    const callout::Priority& i_priority,
171                                    bool i_guard)
172 {
173     nlohmann::json callout;
174 
175     callout["LocationCode"] = util::pdbg::getLocationCode(i_target);
176     callout["Priority"]     = i_priority.getUserDataString();
177     callout["Deconfigured"] = false;
178     callout["Guarded"]      = false; // default
179 
180     // Check if guard info should be added.
181     if (i_guard)
182     {
183         auto guardType = queryGuardPolicy();
184 
185         if (!(callout::GuardType::NONE == guardType))
186         {
187             callout["Guarded"]    = true;
188             callout["EntityPath"] = util::pdbg::getPhysBinPath(i_target);
189             callout["GuardType"]  = guardType.getString();
190         }
191     }
192 
193     addCallout(callout);
194 }
195 
196 //------------------------------------------------------------------------------
197 
198 void ServiceData::addBackplaneCallout(const callout::Priority& i_priority)
199 {
200     // TODO: There isn't a device tree object for this. So will need to hardcode
201     //       the location code for now. In the future, we will need a mechanism
202     //       to make this data driven.
203 
204     nlohmann::json callout;
205 
206     callout["LocationCode"] = "P0";
207     callout["Priority"]     = i_priority.getUserDataString();
208     callout["Deconfigured"] = false;
209     callout["Guarded"]      = false;
210 
211     addCallout(callout);
212 }
213 
214 //------------------------------------------------------------------------------
215 
216 } // namespace analyzer
217