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