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