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