1 #pragma once 2 3 #include "constants.hpp" 4 #include "logger.hpp" 5 #include "types.hpp" 6 7 #include <nlohmann/json.hpp> 8 9 #include <mutex> 10 #include <optional> 11 #include <semaphore> 12 #include <tuple> 13 14 namespace vpd 15 { 16 /** 17 * @brief A class to process and publish VPD data. 18 * 19 * The class works on VPD and is mainly responsible for following tasks: 20 * 1) Select appropriate device tree and JSON. Reboot if required. 21 * 2) Get desired parser using parser factory. 22 * 3) Calling respective parser class to get parsed VPD. 23 * 4) Arranging VPD data under required interfaces. 24 * 5) Calling PIM to publish VPD. 25 * 26 * The class may also implement helper functions required for VPD handling. 27 */ 28 class Worker 29 { 30 public: 31 /** 32 * List of deleted functions. 33 */ 34 Worker(const Worker&) = delete; 35 Worker& operator=(const Worker&) = delete; 36 Worker(Worker&&) = delete; 37 Worker& operator=(const Worker&&) = delete; 38 39 /** 40 * @brief Constructor. 41 * 42 * In case the processing is not JSON based, no argument needs to be passed. 43 * Constructor will also, based on symlink pick the correct JSON and 44 * initialize the parsed JSON variable. 45 * 46 * @param[in] pathToConfigJSON - Path to the config JSON, if applicable. 47 * @param[in] i_maxThreadCount - Maximum thread while collecting FRUs VPD. 48 * @param[in] i_vpdCollectionMode - Mode in which VPD collection should take 49 * place. 50 * 51 * Note: Throws std::exception in case of construction failure. Caller needs 52 * to handle to detect successful object creation. 53 */ 54 Worker(std::string pathToConfigJson = std::string(), 55 uint8_t i_maxThreadCount = constants::MAX_THREADS, 56 types::VpdCollectionMode i_vpdCollectionMode = 57 types::VpdCollectionMode::DEFAULT_MODE); 58 59 /** 60 * @brief Destructor 61 */ 62 ~Worker() = default; 63 64 /** 65 * @brief API to process all FRUs presnt in config JSON file. 66 * 67 * This API based on config JSON passed/selected for the system, will 68 * trigger parser for all the FRUs and publish it on DBus. 69 * 70 * Note: Config JSON file path should be passed to worker class constructor 71 * to make use of this API. 72 * 73 */ 74 void collectFrusFromJson(); 75 76 /** 77 * @brief API to parse VPD data 78 * 79 * @param[in] i_vpdFilePath - Path to the VPD file. 80 */ 81 types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath); 82 83 /** 84 * @brief An API to populate DBus interfaces for a FRU. 85 * 86 * Note: Call this API to populate D-Bus. Also caller should handle empty 87 * objectInterfaceMap. 88 * 89 * @param[in] parsedVpdMap - Parsed VPD as a map. 90 * @param[out] objectInterfaceMap - Object and its interfaces map. 91 * @param[in] vpdFilePath - EEPROM path of FRU. 92 */ 93 void populateDbus(const types::VPDMapVariant& parsedVpdMap, 94 types::ObjectMap& objectInterfaceMap, 95 const std::string& vpdFilePath); 96 97 /** 98 * @brief An API to delete FRU VPD over DBus. 99 * 100 * @param[in] i_dbusObjPath - Dbus object path of the FRU. 101 * 102 * @throw std::runtime_error if given input path is empty. 103 */ 104 void deleteFruVpd(const std::string& i_dbusObjPath); 105 106 /** 107 * @brief API to get status of VPD collection process. 108 * 109 * @return - True when done, false otherwise. 110 */ isAllFruCollectionDone() const111 inline bool isAllFruCollectionDone() const 112 { 113 return m_isAllFruCollected; 114 } 115 116 /** 117 * @brief API to get system config JSON object 118 * 119 * @return System config JSON object. 120 */ getSysCfgJsonObj() const121 inline nlohmann::json getSysCfgJsonObj() const 122 { 123 return m_parsedJson; 124 } 125 126 /** 127 * @brief API to get active thread count. 128 * 129 * Each FRU is collected in a separate thread. This API gives the active 130 * thread collecting FRU's VPD at any given time. 131 * 132 * @return Count of active threads. 133 */ getActiveThreadCount() const134 size_t getActiveThreadCount() const 135 { 136 return m_activeCollectionThreadCount; 137 } 138 139 /** 140 * @brief API to get list of EEPROMs for which thread creation failed. 141 * 142 * This API returns reference to list of EEPROM paths for which VPD 143 * collection thread creation has failed. Manager needs to process this list 144 * of EEPROMs and take appropriate action. 145 * 146 * @return reference to list of EEPROM paths for which VPD collection thread 147 * creation has failed 148 */ getFailedEepromPaths()149 inline std::forward_list<std::string>& getFailedEepromPaths() noexcept 150 { 151 return m_failedEepromPaths; 152 } 153 154 /** 155 * @brief API to get VPD collection mode 156 * 157 * @return VPD collection mode enum value 158 */ getVpdCollectionMode() const159 inline types::VpdCollectionMode getVpdCollectionMode() const 160 { 161 return m_vpdCollectionMode; 162 } 163 164 /** 165 * @brief Collect single FRU VPD 166 * API can be used to perform VPD collection for the given FRU, only if the 167 * current state of the system matches with the state at which the FRU is 168 * allowed for VPD recollection. 169 * 170 * @param[in] i_dbusObjPath - D-bus object path 171 */ 172 void collectSingleFruVpd( 173 const sdbusplus::message::object_path& i_dbusObjPath); 174 175 /** 176 * @brief Perform VPD recollection 177 * This api will trigger parser to perform VPD recollection for FRUs that 178 * can be replaced at standby. 179 */ 180 void performVpdRecollection(); 181 182 private: 183 /** 184 * @brief An API to parse and publish a FRU VPD over D-Bus. 185 * 186 * Note: This API will handle all the exceptions internally and will only 187 * return status of parsing and publishing of VPD over D-Bus. 188 * 189 * @param[in] i_vpdFilePath - Path of file containing VPD. 190 * @return Tuple of status and file path. Status, true if successfull else 191 * false. 192 */ 193 std::tuple<bool, std::string> parseAndPublishVPD( 194 const std::string& i_vpdFilePath); 195 196 /** 197 * @brief An API to process extrainterfaces w.r.t a FRU. 198 * 199 * @param[in] singleFru - JSON block for a single FRU. 200 * @param[out] interfaces - Map to hold interface along with its properties. 201 * @param[in] parsedVpdMap - Parsed VPD as a map. 202 */ 203 void processExtraInterfaces(const nlohmann::json& singleFru, 204 types::InterfaceMap& interfaces, 205 const types::VPDMapVariant& parsedVpdMap); 206 207 /** 208 * @brief An API to process embedded and synthesized FRUs. 209 * 210 * @param[in] singleFru - FRU to be processed. 211 * @param[out] interfaces - Map to hold interface along with its properties. 212 */ 213 void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru, 214 types::InterfaceMap& interfaces); 215 216 /** 217 * @brief An API to read process FRU based in CCIN. 218 * 219 * For some FRUs VPD can be processed only if the FRU has some specific 220 * value for CCIN. In case the value is not from that set, VPD for those 221 * FRUs can't be processed. 222 * 223 * @param[in] singleFru - Fru whose CCIN value needs to be matched. 224 * @param[in] parsedVpdMap - Parsed VPD map. 225 */ 226 bool processFruWithCCIN(const nlohmann::json& singleFru, 227 const types::VPDMapVariant& parsedVpdMap); 228 229 /** 230 * @brief API to process json's inherit flag. 231 * 232 * Inherit flag denotes that some property in the child FRU needs to be 233 * inherited from parent FRU. 234 * 235 * @param[in] parsedVpdMap - Parsed VPD as a map. 236 * @param[out] interfaces - Map to hold interface along with its properties. 237 */ 238 void processInheritFlag(const types::VPDMapVariant& parsedVpdMap, 239 types::InterfaceMap& interfaces); 240 241 /** 242 * @brief API to process json's "copyRecord" flag. 243 * 244 * copyRecord flag denotes if some record data needs to be copies in the 245 * given FRU. 246 * 247 * @param[in] singleFru - FRU being processed. 248 * @param[in] parsedVpdMap - Parsed VPD as a map. 249 * @param[out] interfaces - Map to hold interface along with its properties. 250 */ 251 void processCopyRecordFlag(const nlohmann::json& singleFru, 252 const types::VPDMapVariant& parsedVpdMap, 253 types::InterfaceMap& interfaces); 254 255 /** 256 * @brief An API to populate IPZ VPD property map. 257 * 258 * @param[out] interfacePropMap - Map of interface and properties under it. 259 * @param[in] keyordValueMap - Keyword value map of IPZ VPD. 260 * @param[in] interfaceName - Name of the interface. 261 */ 262 void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap, 263 const types::IPZKwdValueMap& keyordValueMap, 264 const std::string& interfaceName); 265 266 /** 267 * @brief An API to populate Kwd VPD property map. 268 * 269 * @param[in] keyordValueMap - Keyword value map of Kwd VPD. 270 * @param[out] interfaceMap - interface and property,value under it. 271 */ 272 void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap, 273 types::InterfaceMap& interfaceMap); 274 275 /** 276 * @brief API to populate all required interface for a FRU. 277 * 278 * @param[in] interfaceJson - JSON containing interfaces to be populated. 279 * @param[out] interfaceMap - Map to hold populated interfaces. 280 * @param[in] parsedVpdMap - Parsed VPD as a map. 281 */ 282 void populateInterfaces(const nlohmann::json& interfaceJson, 283 types::InterfaceMap& interfaceMap, 284 const types::VPDMapVariant& parsedVpdMap); 285 286 /** 287 * @brief Check if the given CPU is an IO only chip. 288 * 289 * The CPU is termed as IO, whose all of the cores are bad and can never be 290 * used. Those CPU chips can be used for IO purpose like connecting PCIe 291 * devices etc., The CPU whose every cores are bad, can be identified from 292 * the CP00 record's PG keyword, only if all of the 8 EQs' value equals 293 * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.) 294 * 295 * @param [in] pgKeyword - PG Keyword of CPU. 296 * @return true if the given cpu is an IO, false otherwise. 297 */ 298 bool isCPUIOGoodOnly(const std::string& pgKeyword); 299 300 /** 301 * @brief API to process preAction(base_action) defined in config JSON. 302 * 303 * @note sequence of tags under any given flag of preAction is EXTREMELY 304 * important to ensure proper processing. The API will process all the 305 * nested items under the base action sequentially. Also if any of the tag 306 * processing fails, the code will not process remaining tags under the 307 * flag. 308 * ******** sample format ************** 309 * fru EEPROM path: { 310 * base_action: { 311 * flag1: { 312 * tag1: { 313 * }, 314 * tag2: { 315 * } 316 * } 317 * flag2: { 318 * tags: { 319 * } 320 * } 321 * } 322 * } 323 * ************************************* 324 * 325 * @param[in] i_vpdFilePath - Path to the EEPROM file. 326 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 327 * processed under PreAction tag of config JSON. 328 * @param[out] o_errCode - To set error code in case of error. 329 * @return Execution status. 330 */ 331 bool processPreAction(const std::string& i_vpdFilePath, 332 const std::string& i_flagToProcess, 333 uint16_t& o_errCode); 334 335 /** 336 * @brief API to process postAction(base_action) defined in config JSON. 337 * 338 * @note Sequence of tags under any given flag of postAction is EXTREMELY 339 * important to ensure proper processing. The API will process all the 340 * nested items under the base action sequentially. Also if any of the tag 341 * processing fails, the code will not process remaining tags under the 342 * flag. 343 * ******** sample format ************** 344 * fru EEPROM path: { 345 * base_action: { 346 * flag1: { 347 * tag1: { 348 * }, 349 * tag2: { 350 * } 351 * } 352 * flag2: { 353 * tags: { 354 * } 355 * } 356 * } 357 * } 358 * ************************************* 359 * Also, if post action is required to be processed only for FRUs with 360 * certain CCIN then CCIN list can be provided under flag. 361 * 362 * @param[in] i_vpdFruPath - Path to the EEPROM file. 363 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 364 * processed under postAction tag of config JSON. 365 * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is 366 * required. 367 * @return Execution status. 368 */ 369 bool processPostAction( 370 const std::string& i_vpdFruPath, const std::string& i_flagToProcess, 371 const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt); 372 373 /** 374 * @brief API to update "Functional" property. 375 * 376 * The API sets the default value for "Functional" property once if the 377 * property is not yet populated over DBus. As the property value is not 378 * controlled by the VPD-Collection process, if it is found already 379 * populated, the functions skips re-populating the property so that already 380 * existing value can be retained. 381 * 382 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 383 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 384 */ 385 void processFunctionalProperty(const std::string& i_inventoryObjPath, 386 types::InterfaceMap& io_interfaces); 387 388 /** 389 * @brief API to update "enabled" property. 390 * 391 * The API sets the default value for "enabled" property once if the 392 * property is not yet populated over DBus. As the property value is not 393 * controlled by the VPD-Collection process, if it is found already 394 * populated, the functions skips re-populating the property so that already 395 * existing value can be retained. 396 * 397 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 398 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 399 */ 400 void processEnabledProperty(const std::string& i_inventoryObjPath, 401 types::InterfaceMap& io_interfaces); 402 403 /** 404 * @brief API to set present property. 405 * 406 * This API updates the present property of the given FRU with the given 407 * value. Note: It is the responsibility of the caller to determine whether 408 * the present property for the FRU should be updated or not. 409 * 410 * @param[in] i_vpdPath - EEPROM or inventory path. 411 * @param[in] i_value - value to be set. 412 */ 413 void setPresentProperty(const std::string& i_fruPath, const bool& i_value); 414 415 /** 416 * @brief API to check if the path needs to be skipped for collection. 417 * 418 * Some FRUs, under some given scenarios should not be collected and 419 * skipped. 420 * 421 * @param[in] i_vpdFilePath - EEPROM path. 422 * 423 * @return True - if path is empty or should be skipped, false otherwise. 424 */ 425 bool skipPathForCollection(const std::string& i_vpdFilePath); 426 427 /** 428 * @brief API to check if present property should be handled for given FRU. 429 * 430 * vpd-manager should update present property for a FRU if and only if it's 431 * not synthesized and vpd-manager handles present property for the FRU. 432 * This API assumes "handlePresence" tag is a subset of "synthesized" tag. 433 * 434 * @param[in] i_fru - JSON block for a single FRU. 435 * 436 * @return true if present property should be handled, false otherwise. 437 */ isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const438 inline bool isPresentPropertyHandlingRequired( 439 const nlohmann::json& i_fru) const noexcept 440 { 441 // TODO: revisit this to see if this logic can be optimized. 442 return !i_fru.value("synthesized", false) && 443 i_fru.value("handlePresence", true); 444 } 445 446 // Parsed JSON file. 447 nlohmann::json m_parsedJson{}; 448 449 // Path to config JSON if applicable. 450 std::string& m_configJsonPath; 451 452 // Keeps track of active thread(s) doing VPD collection. 453 size_t m_activeCollectionThreadCount = 0; 454 455 // Holds status, if VPD collection has been done or not. 456 // Note: This variable does not give information about successfull or failed 457 // collection. It just states, if the VPD collection process is over or not. 458 bool m_isAllFruCollected = false; 459 460 // Mutex to guard critical resource m_activeCollectionThreadCount. 461 std::mutex m_mutex; 462 463 // Counting semaphore to limit the number of threads. 464 std::counting_semaphore<constants::MAX_THREADS> m_semaphore; 465 466 // List of EEPROM paths for which VPD collection thread creation has failed. 467 std::forward_list<std::string> m_failedEepromPaths; 468 469 // VPD collection mode 470 types::VpdCollectionMode m_vpdCollectionMode{ 471 types::VpdCollectionMode::DEFAULT_MODE}; 472 473 // Shared pointer to Logger object 474 std::shared_ptr<Logger> m_logger; 475 }; 476 } // namespace vpd 477