1 #pragma once 2 #include "new_power_supply.hpp" 3 #include "types.hpp" 4 #include "utility.hpp" 5 6 #include <phosphor-logging/lg2.hpp> 7 #include <sdbusplus/bus.hpp> 8 #include <sdbusplus/bus/match.hpp> 9 #include <sdbusplus/server/manager.hpp> 10 #include <sdbusplus/server/object.hpp> 11 #include <sdeventplus/event.hpp> 12 #include <sdeventplus/utility/timer.hpp> 13 #include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp> 14 15 #include <filesystem> 16 #include <map> 17 #include <string> 18 #include <vector> 19 20 struct SupportedPsuConfiguration 21 { 22 int powerSupplyCount; 23 std::vector<uint64_t> inputVoltage; 24 bool powerConfigFullLoad; 25 }; 26 27 using namespace phosphor::power::psu; 28 using namespace phosphor::power::util; 29 using namespace sdeventplus; 30 31 namespace phosphor::power::chassis 32 { 33 34 constexpr uint64_t invalidObjectPathUniqueId = 9999; 35 using PowerSystemInputsInterface = sdbusplus::xyz::openbmc_project::State:: 36 Decorator::server::PowerSystemInputs; 37 using PowerSystemInputsObject = 38 sdbusplus::server::object_t<PowerSystemInputsInterface>; 39 40 // Validation timeout. Allow 30s to detect if new EM interfaces show up in D-Bus 41 // before performing the validation. 42 // Previously the timer was set to 10 seconds was too short, it results in 43 // incorrect errors being logged, but no real consequence of longer timeout. 44 constexpr auto validationTimeout = std::chrono::seconds(30); 45 46 /** 47 * @class PowerSystemInputs 48 * @brief A concrete implementation for the PowerSystemInputs interface. 49 */ 50 class PowerSystemInputs : public PowerSystemInputsObject 51 { 52 public: PowerSystemInputs(sdbusplus::bus_t & bus,const std::string & path)53 PowerSystemInputs(sdbusplus::bus_t& bus, const std::string& path) : 54 PowerSystemInputsObject(bus, path.c_str()) 55 {} 56 }; 57 58 /** 59 * @class Chassis 60 * 61 * @brief This class will create an object used to manage and monitor a list of 62 * power supply devices attached to the chassis. 63 */ 64 class Chassis 65 { 66 public: 67 Chassis() = delete; 68 ~Chassis() = default; 69 Chassis(const Chassis&) = delete; 70 Chassis& operator=(const Chassis&) = delete; 71 Chassis(Chassis&&) = delete; 72 Chassis& operator=(Chassis&&) = delete; 73 74 /** 75 * @brief Constructor to read configuration from D-Bus. 76 * 77 * @param[in] bus - D-Bus bus object 78 * @param[in] chassisPath - Chassis path 79 * @param[in] chassisName - Chassis name 80 * @param[in] event - Event loop object 81 */ 82 Chassis(sdbusplus::bus_t& bus, const std::string& chassisPath, 83 const std::string& chassisName, const sdeventplus::Event& e); 84 85 /** 86 * @brief Retrieves the unique identifier of the chassis. 87 * 88 * @return uint64_t The unique 64 bits identifier of the chassis. 89 */ getChassisId()90 uint64_t getChassisId() 91 { 92 return chassisPathUniqueId; 93 } 94 95 /** 96 * @brief Analyze the status of each of the power supplies. Log errors for 97 * faults, when and where appropriate. 98 */ 99 void analyze(); 100 101 /** 102 * @brief Get the status of Power on. 103 */ isPowerOn()104 bool isPowerOn() 105 { 106 return powerOn; 107 } 108 109 /** 110 * @brief Initialize power monitoring infrastructure for Chassis. 111 * Sets up configuration validation timer, attempts to create GPIO, 112 * subscribe to D-Bus power state change events. 113 */ 114 void initPowerMonitoring(); 115 116 /** 117 * @brief Handles addition of the SupportedConfiguration interface. 118 * This function triggered when the SupportedConfiguration interface added 119 * to a D-Bus object. The function calls populateSupportedConfiguration() 120 * and updateMissingPSUs() to processes the provided properties. 121 * 122 * @param properties A map of D-Bus properties associated with the 123 * SupportedConfiguration interface. 124 */ 125 void supportedConfigurationInterfaceAdded( 126 const util::DbusPropertyMap& properties); 127 128 /** 129 * @brief Handle the addition of PSU interface. 130 * This function is called when a Power Supply interface added to a D-Bus. 131 * This function calls getPSUProperties() and updateMissingPSUs(). 132 * 133 * @param properties A map of D-Bus properties for the PSU interface. 134 */ 135 void psuInterfaceAdded(util::DbusPropertyMap& properties); 136 137 /** 138 * @brief Call to validate the psu configuration if the power is on and both 139 * the IBMCFFPSConnector and SupportedConfiguration interfaces have been 140 * processed 141 */ validatePsuConfigAndInterfacesProcessed()142 void validatePsuConfigAndInterfacesProcessed() 143 { 144 if (powerOn && !psus.empty() && !supportedConfigs.empty()) 145 { 146 validationTimer->restartOnce(validationTimeout); 147 } 148 }; 149 150 private: 151 /** 152 * @brief The D-Bus object 153 */ 154 sdbusplus::bus_t& bus; 155 156 /** 157 * @brief The timer that performs power supply validation as the entity 158 * manager interfaces show up in d-bus. 159 */ 160 std::unique_ptr< 161 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 162 validationTimer; 163 164 /** @brief True if the power is on. */ 165 bool powerOn = false; 166 167 /** @brief True if power control is in the window between chassis pgood loss 168 * and power off. 169 */ 170 bool powerFaultOccurring = false; 171 172 /** @brief True if an error for a brownout has already been logged. */ 173 bool brownoutLogged = false; 174 175 /** @brief Used as part of subscribing to power on state changes*/ 176 std::string powerService; 177 178 /** @brief Used to subscribe to D-Bus power on state changes */ 179 std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch; 180 181 /** @brief Used to subscribe to D-Bus power supply presence changes */ 182 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> presenceMatches; 183 184 /** 185 * @brief Flag to indicate if the validateConfig() function should be run. 186 * Set to false once the configuration has been validated to avoid 187 * running multiple times due to interfaces added signal. Set to 188 * true during power off to trigger the validation on power on. 189 */ 190 bool runValidateConfig = true; 191 192 /** 193 * @brief Map of supported PSU configurations that include the model name 194 * and their properties. 195 */ 196 std::map<std::string, SupportedPsuConfiguration> supportedConfigs; 197 198 /** 199 * @brief The vector for power supplies. 200 */ 201 std::vector<std::unique_ptr<PowerSupply>> psus; 202 203 /** 204 * @brief The device driver name for all power supplies. 205 */ 206 std::string driverName; 207 208 /** 209 * @brief The libgpiod object for setting the power supply config 210 */ 211 std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr; 212 213 /** 214 * @brief Chassis D-Bus object path 215 */ 216 std::string chassisPath; 217 218 /** 219 * @brief Chassis name; 220 */ 221 std::string chassisShortName; 222 223 /** 224 * @brief The Chassis path unique ID 225 * 226 * Note: chassisPathUniqueId must be declared before powerSystemInputs. 227 */ 228 uint64_t chassisPathUniqueId = invalidObjectPathUniqueId; 229 230 /** 231 * @brief PowerSystemInputs object 232 */ 233 PowerSystemInputs powerSystemInputs; 234 235 /** 236 * @brief ObjectManager path 237 */ 238 std::string objectManagerPath; 239 240 /** 241 * @brief Implement the objectManager for PowerSystemInputs object. 242 * 243 * Implements the org.freedesktop.DBus.ObjectManager interface used to 244 * communicate updates to the PowerSystemInputs object on the 245 * /xyz/openbmc_project/power/power_supplies/{}/psus (where {} is 246 * replaced with chassisX) root D-Bus path. 247 */ 248 sdbusplus::server::manager_t objectManager; 249 250 /** 251 * @brief Implement the ObjectManager for the input voltage rating. 252 * 253 * Implements the org.freedesktop.DBus.ObjectManager interface used to 254 * communicate updates to the input voltage ratings on the 255 * /xyz/openbmc_project/sensors root D-Bus path. 256 */ 257 sdbusplus::server::manager_t sensorsObjManager; 258 259 /** 260 * @brief Declares a constant reference to an sdeventplus::Event to manage 261 * async processing. 262 */ 263 const sdeventplus::Event& eventLoop; 264 265 /** 266 * @brief GPIO to toggle to 'sync' power supply input history. 267 */ 268 std::unique_ptr<GPIOInterfaceBase> syncHistoryGPIO = nullptr; 269 270 /** 271 * @brief Get PSU properties from D-Bus, use that to build a power supply 272 * object. 273 * 274 * @param[in] properties - A map of property names and values 275 */ 276 void getPSUProperties(util::DbusPropertyMap& properties); 277 278 /** 279 * @brief Get PSU configuration from D-Bus 280 */ 281 void getPSUConfiguration(); 282 283 /** 284 * @brief Queries D-Bus for chassis configuration provided by the Entity 285 * Manager. Matches the object against the current chassis unique ID. Upon 286 * finding a match calls populateSupportedConfiguration(). 287 */ 288 void getSupportedConfiguration(); 289 290 /** 291 * @brief Callback for inventory property changes 292 * 293 * Process change of the Power Supply presence. 294 * 295 * @param[in] msg - Data associated with the Present change signal 296 **/ 297 void psuPresenceChanged(sdbusplus::message_t& msg); 298 299 /** 300 * @brief Helper function to populate the PSU supported configuration 301 * 302 * @param[in] properties - A map of property names and values 303 */ 304 void populateSupportedConfiguration( 305 const util::DbusPropertyMap& properties); 306 307 /** 308 * @brief Build the device driver name for the power supply. 309 * 310 * @param[in] i2cbus - i2c bus 311 * @param[in] i2caddr - i2c bus address 312 */ 313 void buildDriverName(uint64_t i2cbus, uint64_t i2caddr); 314 315 /** 316 * @brief Find PSU with device driver name, then populate the device 317 * driver name to all PSUs (including missing PSUs). 318 */ 319 void populateDriverName(); 320 321 /** 322 * @brief Get chassis path unique ID. 323 * 324 * @param [in] path - Chassis path. 325 * @return uint64_t - Chassis path unique ID. 326 */ 327 uint64_t getChassisPathUniqueId(const std::string& path); 328 329 /** 330 * @brief Initializes the chassis. 331 * 332 */ 333 void initialize(); 334 335 /** 336 * @brief Perform power supply configuration validation. 337 * @details Validates if the existing power supply properties are a 338 * supported configuration, and acts on its findings such as logging 339 * errors. 340 */ 341 void validateConfig(); 342 343 /** 344 * @brief Analyze the set of the power supplies for a brownout failure. Log 345 * error when necessary, clear brownout condition when window has passed. 346 */ 347 void analyzeBrownout(); 348 349 /** 350 * @brief Toggles the GPIO to sync power supply input history readings 351 * @details This GPIO is connected to all supplies. This will clear the 352 * previous readings out of the supplies and restart them both at the 353 * same time zero and at record ID 0. The supplies will return 0 354 * bytes of data for the input history command right after this until 355 * a new entry shows up. 356 * 357 * This will cause the code to delete all previous history data and 358 * start fresh. 359 */ 360 void syncHistory(); 361 362 /** 363 * @brief Tells each PSU to set its power supply input 364 * voltage rating D-Bus property. 365 */ setInputVoltageRating()366 inline void setInputVoltageRating() 367 { 368 for (auto& psu : psus) 369 { 370 psu->setInputVoltageRating(); 371 } 372 } 373 374 /** 375 * Create an error 376 * 377 * @param[in] faultName - 'name' message for the BMC error log entry 378 * @param[in,out] additionalData - The AdditionalData property for the error 379 */ 380 void createError(const std::string& faultName, 381 std::map<std::string, std::string>& additionalData); 382 383 /** 384 * @brief Check that all PSUs have the same model name and that the system 385 * has the required number of PSUs present as specified in the Supported 386 * Configuration interface. 387 * 388 * @param[out] additionalData - Contains debug information on why the check 389 * might have failed. Can be used to fill in error logs. 390 * @return true if all the required PSUs are present, false otherwise. 391 */ 392 bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData); 393 394 /** 395 * @brief Update inventory for missing required power supplies 396 */ 397 void updateMissingPSUs(); 398 399 /** 400 * @brief Callback for power state property changes 401 * 402 * Process changes to the powered on state property for the chassis. 403 * 404 * @param[in] msg - Data associated with the power state signal 405 */ 406 void powerStateChanged(sdbusplus::message_t& msg); 407 408 /** 409 * @breif Attempt to create GPIO 410 */ 411 void attemptToCreatePowerConfigGPIO(); 412 413 /** 414 * Write PMBus ON_OFF_CONFIG 415 * 416 * This function will be called to cause the PMBus device driver to send the 417 * ON_OFF_CONFIG command. Takes one byte of data. 418 */ onOffConfig(const uint8_t data)419 void onOffConfig(const uint8_t data) 420 { 421 for (auto& psu : psus) 422 { 423 psu->onOffConfig(data); 424 } 425 } 426 427 /** 428 * This function will be called in various situations in order to clear 429 * any fault status bits that may have been set, in order to start over 430 * with a clean state. Presence changes and power state changes will want 431 * to clear any faults logged. 432 */ clearFaults()433 void clearFaults() 434 { 435 setPowerSupplyError(""); 436 for (auto& psu : psus) 437 { 438 psu->clearFaults(); 439 } 440 } 441 442 /** 443 * Let power control/sequencer application know of PSU error(s). 444 * 445 * @param[in] psuErrorString - string for power supply error 446 */ 447 void setPowerSupplyError(const std::string& psuErrorString); 448 449 /** 450 * @brief Set the power-config-full-load GPIO depending on the EM full load 451 * property value. 452 */ 453 void setPowerConfigGPIO(); 454 455 /** 456 * @brief Helper function to validate that all PSUs have the same model name 457 * 458 * @param[out] model - The model name. Empty if there is a mismatch. 459 * @param[out] additionalData - If there is a mismatch, it contains debug 460 * information such as the mismatched model name. 461 * @return true if all the PSUs have the same model name, false otherwise. 462 */ 463 bool validateModelName(std::string& model, 464 std::map<std::string, std::string>& additionalData); 465 466 /** 467 * @brief Returns the number of PSUs that are required to be present. 468 * 469 * @return required number of PSUs, or 0 if the number could not be 470 * determined. 471 */ 472 unsigned int getRequiredPSUCount(); 473 474 /** 475 * @brief Returns whether the specified PSU is required to be present. 476 * 477 * @param[in] psu - Power supply to check 478 * @return true if PSU is required, false otherwise. 479 */ 480 bool isRequiredPSU(const PowerSupply& psu); 481 }; 482 483 } // namespace phosphor::power::chassis 484