1 #include <analyzer/service_data.hpp> 2 3 namespace analyzer 4 { 5 6 //------------------------------------------------------------------------------ 7 8 void ServiceData::calloutTarget(pdbg_target* i_target, 9 callout::Priority i_priority, bool i_guard) 10 { 11 // Add the target to the callout list. 12 addTargetCallout(i_target, i_priority, i_guard); 13 14 // Add the callout FFDC. 15 nlohmann::json ffdc; 16 ffdc["Callout Type"] = "Hardware Callout"; 17 ffdc["Target"] = util::pdbg::getPhysDevPath(i_target); 18 ffdc["Priority"] = callout::getStringFFDC(i_priority); 19 ffdc["Guard"] = i_guard; 20 addCalloutFFDC(ffdc); 21 setSrcSubsystem(getTargetSubsystem(i_target), i_priority); 22 } 23 24 //------------------------------------------------------------------------------ 25 26 void ServiceData::calloutConnected(pdbg_target* i_rxTarget, 27 const callout::BusType& i_busType, 28 callout::Priority i_priority, bool i_guard) 29 { 30 // Get the endpoint target for the transfer side of the bus. 31 auto txTarget = util::pdbg::getConnectedTarget(i_rxTarget, i_busType); 32 33 // Callout the TX endpoint. 34 addTargetCallout(txTarget, i_priority, i_guard); 35 36 // Add the callout FFDC. 37 nlohmann::json ffdc; 38 ffdc["Callout Type"] = "Connected Callout"; 39 ffdc["Bus Type"] = i_busType.getString(); 40 ffdc["RX Target"] = util::pdbg::getPhysDevPath(i_rxTarget); 41 ffdc["TX Target"] = util::pdbg::getPhysDevPath(txTarget); 42 ffdc["Priority"] = callout::getStringFFDC(i_priority); 43 ffdc["Guard"] = i_guard; 44 addCalloutFFDC(ffdc); 45 setSrcSubsystem(getTargetSubsystem(txTarget), i_priority); 46 } 47 48 //------------------------------------------------------------------------------ 49 50 void ServiceData::calloutBus(pdbg_target* i_rxTarget, 51 const callout::BusType& i_busType, 52 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"] = callout::getStringFFDC(i_priority); 74 ffdc["Guard"] = i_guard; 75 addCalloutFFDC(ffdc); 76 setSrcSubsystem(i_busType.getSrcSubsystem(), i_priority); 77 } 78 79 //------------------------------------------------------------------------------ 80 81 void ServiceData::calloutClock(const callout::ClockType& i_clockType, 82 callout::Priority i_priority, bool) 83 { 84 // Callout the clock target. 85 // TODO: For P10, the callout is simply the backplane. Also, there are no 86 // clock targets in the device tree. So at the moment there is no 87 // guard support for clock targets. 88 addBackplaneCallout(i_priority); 89 90 // Add the callout FFDC. 91 // TODO: Add the target and guard type if guard is ever supported. 92 nlohmann::json ffdc; 93 ffdc["Callout Type"] = "Clock Callout"; 94 ffdc["Clock Type"] = i_clockType.getString(); 95 ffdc["Priority"] = callout::getStringFFDC(i_priority); 96 addCalloutFFDC(ffdc); 97 setSrcSubsystem(i_clockType.getSrcSubsystem(), i_priority); 98 } 99 100 //------------------------------------------------------------------------------ 101 102 void ServiceData::calloutProcedure(const callout::Procedure& i_procedure, 103 callout::Priority i_priority) 104 { 105 // Add the actual callout to the service data. 106 nlohmann::json callout; 107 callout["Procedure"] = i_procedure.getString(); 108 callout["Priority"] = callout::getString(i_priority); 109 addCallout(callout); 110 111 // Add the callout FFDC. 112 nlohmann::json ffdc; 113 ffdc["Callout Type"] = "Procedure Callout"; 114 ffdc["Procedure"] = i_procedure.getString(); 115 ffdc["Priority"] = callout::getStringFFDC(i_priority); 116 addCalloutFFDC(ffdc); 117 setSrcSubsystem(i_procedure.getSrcSubsystem(), i_priority); 118 } 119 120 //------------------------------------------------------------------------------ 121 122 void ServiceData::calloutPart(const callout::PartType& i_part, 123 callout::Priority i_priority) 124 { 125 if (callout::PartType::PNOR == i_part) 126 { 127 // The PNOR is on the BMC card. 128 // TODO: Will need to be modified if we ever support systems with more 129 // than one BMC. 130 addTargetCallout(util::pdbg::getTrgt("/bmc0"), i_priority, false); 131 } 132 else 133 { 134 throw std::logic_error("Unsupported part type: " + i_part.getString()); 135 } 136 137 // Add the callout FFDC. 138 nlohmann::json ffdc; 139 ffdc["Callout Type"] = "Part Callout"; 140 ffdc["Part Type"] = i_part.getString(); 141 ffdc["Priority"] = callout::getStringFFDC(i_priority); 142 addCalloutFFDC(ffdc); 143 setSrcSubsystem(i_part.getSrcSubsystem(), i_priority); 144 } 145 146 //------------------------------------------------------------------------------ 147 148 void ServiceData::addCallout(const nlohmann::json& i_callout) 149 { 150 // The new callout is either a hardware callout with a location code or a 151 // procedure callout. 152 153 std::string type{}; 154 if (i_callout.contains("LocationCode")) 155 { 156 type = "LocationCode"; 157 } 158 else if (i_callout.contains("Procedure")) 159 { 160 type = "Procedure"; 161 } 162 else 163 { 164 throw std::logic_error("Unsupported callout: " + i_callout.dump()); 165 } 166 167 // A map to determine the priority order. All of the medium priorities, 168 // including the medium group priorities, are all the same level. 169 // clang-format off 170 static const std::map<std::string, unsigned int> m = { 171 {callout::getString(callout::Priority::HIGH), 3}, 172 {callout::getString(callout::Priority::MED), 2}, 173 {callout::getString(callout::Priority::MED_A), 2}, 174 {callout::getString(callout::Priority::MED_B), 2}, 175 {callout::getString(callout::Priority::MED_C), 2}, 176 {callout::getString(callout::Priority::LOW), 1}, 177 }; 178 // clang-format on 179 180 // The new callout must contain a valid priority. 181 assert(i_callout.contains("Priority") && 182 m.contains(i_callout.at("Priority"))); 183 184 bool addCallout = true; 185 186 for (auto& c : iv_calloutList) 187 { 188 if (c.contains(type) && (c.at(type) == i_callout.at(type))) 189 { 190 // The new callout already exists. Don't add a new callout. 191 addCallout = false; 192 193 if (m.at(c.at("Priority")) < m.at(i_callout.at("Priority"))) 194 { 195 // The new callout has a higher priority, update it. 196 c["Priority"] = i_callout.at("Priority"); 197 } 198 } 199 } 200 201 if (addCallout) 202 { 203 iv_calloutList.push_back(i_callout); 204 } 205 } 206 207 //------------------------------------------------------------------------------ 208 209 void ServiceData::addTargetCallout(pdbg_target* i_target, 210 callout::Priority i_priority, bool i_guard) 211 { 212 nlohmann::json callout; 213 214 callout["LocationCode"] = util::pdbg::getLocationCode(i_target); 215 callout["Priority"] = callout::getString(i_priority); 216 callout["Deconfigured"] = false; 217 callout["Guarded"] = false; // default 218 219 // Check if guard info should be added. 220 if (i_guard) 221 { 222 auto guardType = queryGuardPolicy(); 223 224 if (!(callout::GuardType::NONE == guardType)) 225 { 226 callout["Guarded"] = true; 227 callout["EntityPath"] = util::pdbg::getPhysBinPath(i_target); 228 callout["GuardType"] = guardType.getString(); 229 } 230 } 231 232 addCallout(callout); 233 } 234 235 //------------------------------------------------------------------------------ 236 237 void ServiceData::addBackplaneCallout(callout::Priority i_priority) 238 { 239 // TODO: There isn't a device tree object for this. So will need to hardcode 240 // the location code for now. In the future, we will need a mechanism 241 // to make this data driven. 242 243 nlohmann::json callout; 244 245 callout["LocationCode"] = "P0"; 246 callout["Priority"] = callout::getString(i_priority); 247 callout["Deconfigured"] = false; 248 callout["Guarded"] = false; 249 250 addCallout(callout); 251 } 252 253 //------------------------------------------------------------------------------ 254 255 void ServiceData::setSrcSubsystem(callout::SrcSubsystem i_subsystem, 256 callout::Priority i_priority) 257 { 258 // clang-format off 259 static const std::map<callout::Priority, unsigned int> m = 260 { 261 // Note that all medium priorities, including groups A, B, and C, are 262 // the same priority. 263 {callout::Priority::HIGH, 3}, 264 {callout::Priority::MED, 2}, 265 {callout::Priority::MED_A, 2}, 266 {callout::Priority::MED_B, 2}, 267 {callout::Priority::MED_C, 2}, 268 {callout::Priority::LOW, 1}, 269 }; 270 // clang-format on 271 272 // The default subsystem is CEC_HARDWARE with LOW priority. Change the 273 // subsystem if the given subsystem has a higher priority or if the stored 274 // subsystem is still the default. 275 if (m.at(iv_srcSubsystem.second) < m.at(i_priority) || 276 (callout::SrcSubsystem::CEC_HARDWARE == iv_srcSubsystem.first && 277 callout::Priority::LOW == iv_srcSubsystem.second)) 278 { 279 iv_srcSubsystem.first = i_subsystem; 280 iv_srcSubsystem.second = i_priority; 281 } 282 } 283 284 //------------------------------------------------------------------------------ 285 286 callout::SrcSubsystem ServiceData::getTargetSubsystem(pdbg_target* i_target) 287 { 288 using TargetType_t = util::pdbg::TargetType_t; 289 290 // Default the subsystem to CEC_HARDWARE 291 callout::SrcSubsystem o_subSys = callout::SrcSubsystem::CEC_HARDWARE; 292 293 // clang-format off 294 static const std::map<uint8_t, callout::SrcSubsystem> subSysMap = 295 { 296 {TargetType_t::TYPE_DIMM, callout::SrcSubsystem::MEMORY_DIMM }, 297 {TargetType_t::TYPE_PROC, callout::SrcSubsystem::PROCESSOR_FRU }, 298 {TargetType_t::TYPE_CORE, callout::SrcSubsystem::PROCESSOR_UNIT}, 299 {TargetType_t::TYPE_NX, callout::SrcSubsystem::PROCESSOR }, 300 {TargetType_t::TYPE_EQ, callout::SrcSubsystem::PROCESSOR_UNIT}, 301 {TargetType_t::TYPE_PEC, callout::SrcSubsystem::PROCESSOR_UNIT}, 302 {TargetType_t::TYPE_PHB, callout::SrcSubsystem::PHB }, 303 {TargetType_t::TYPE_MC, callout::SrcSubsystem::MEMORY_CTLR }, 304 {TargetType_t::TYPE_IOLINK, callout::SrcSubsystem::PROCESSOR_BUS }, 305 {TargetType_t::TYPE_OMI, callout::SrcSubsystem::MEMORY_CTLR }, 306 {TargetType_t::TYPE_MCC, callout::SrcSubsystem::MEMORY_CTLR }, 307 {TargetType_t::TYPE_OMIC, callout::SrcSubsystem::MEMORY_CTLR }, 308 {TargetType_t::TYPE_OCMB, callout::SrcSubsystem::MEMORY_FRU }, 309 {TargetType_t::TYPE_MEM_PORT, callout::SrcSubsystem::MEMORY_CTLR }, 310 {TargetType_t::TYPE_NMMU, callout::SrcSubsystem::PROCESSOR_UNIT}, 311 {TargetType_t::TYPE_PAU, callout::SrcSubsystem::PROCESSOR_UNIT}, 312 {TargetType_t::TYPE_IOHS, callout::SrcSubsystem::PROCESSOR_UNIT}, 313 {TargetType_t::TYPE_PAUC, callout::SrcSubsystem::PROCESSOR_UNIT}, 314 }; 315 // clang-format on 316 317 auto targetType = util::pdbg::getTrgtType(i_target); 318 319 // If the type of the input target exists in the map, update the output 320 if (subSysMap.count(targetType) > 0) 321 { 322 o_subSys = subSysMap.at(targetType); 323 } 324 325 return o_subSys; 326 } 327 328 //------------------------------------------------------------------------------ 329 330 } // namespace analyzer 331