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 private: 138 /** 139 * The D-Bus object 140 */ 141 sdbusplus::bus_t& bus; 142 143 /** 144 * The timer that runs to periodically check the power supplies. 145 */ 146 std::unique_ptr< 147 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 148 timer; 149 150 /** 151 * The timer that performs power supply validation as the entity manager 152 * interfaces show up in d-bus. 153 */ 154 std::unique_ptr< 155 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 156 validationTimer; 157 158 /** 159 * Let power control/sequencer application know of PSU error(s). 160 * 161 * @param[in] psuErrorString - string for power supply error 162 */ 163 void setPowerSupplyError(const std::string& psuErrorString); 164 165 /** 166 * Create an error 167 * 168 * @param[in] faultName - 'name' message for the BMC error log entry 169 * @param[in,out] additionalData - The AdditionalData property for the error 170 */ 171 void createError(const std::string& faultName, 172 std::map<std::string, std::string>& additionalData); 173 174 /** 175 * Analyze the status of each of the power supplies. 176 * 177 * Log errors for faults, when and where appropriate. 178 */ 179 void analyze(); 180 181 /** @brief True if the power is on. */ 182 bool powerOn = false; 183 184 /** @brief True if power control is in the window between chassis pgood loss 185 * and power off. */ 186 bool powerFaultOccurring = false; 187 188 /** @brief True if an error for a brownout has already been logged. */ 189 bool brownoutLogged = false; 190 191 /** @brief Used as part of subscribing to power on state changes*/ 192 std::string powerService; 193 194 /** @brief Used to subscribe to D-Bus power on state changes */ 195 std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch; 196 197 /** @brief Used to subscribe to D-Bus power supply presence changes */ 198 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> presenceMatches; 199 200 /** @brief Used to subscribe to Entity Manager interfaces added */ 201 std::unique_ptr<sdbusplus::bus::match_t> entityManagerIfacesAddedMatch; 202 203 /** 204 * @brief Callback for power state property changes 205 * 206 * Process changes to the powered on state property for the system. 207 * 208 * @param[in] msg - Data associated with the power state signal 209 */ 210 void powerStateChanged(sdbusplus::message_t& msg); 211 212 /** 213 * @brief Callback for inventory property changes 214 * 215 * Process change of the Present property for power supply. 216 * 217 * @param[in] msg - Data associated with the Present change signal 218 **/ 219 void presenceChanged(sdbusplus::message_t& msg); 220 221 /** 222 * @brief Callback for entity-manager interface added 223 * 224 * Process the information from the supported configuration and or IBM CFFPS 225 * Connector interface being added. 226 * 227 * @param[in] msg - Data associated with the interfaces added signal 228 */ 229 void entityManagerIfaceAdded(sdbusplus::message_t& msg); 230 231 /** 232 * @brief Adds properties to the inventory. 233 * 234 * Reads the values from the devices and writes them to the associated 235 * power supply D-Bus inventory objects. 236 * 237 * This needs to be done on startup, and each time the presence state 238 * changes. 239 */ 240 void updateInventory() 241 { 242 for (auto& psu : psus) 243 { 244 psu->updateInventory(); 245 } 246 } 247 248 /** 249 * @brief Helper function to populate the system properties 250 * 251 * @param[in] properties - A map of property names and values 252 */ 253 void populateSysProperties(const util::DbusPropertyMap& properties); 254 255 /** 256 * @brief Update inventory for missing required power supplies 257 */ 258 void updateMissingPSUs(); 259 260 /** 261 * @brief Perform power supply configuration validation. 262 * @details Validates if the existing power supply properties are a 263 * supported configuration, and acts on its findings such as logging errors. 264 */ 265 void validateConfig(); 266 267 /** 268 * @brief Flag to indicate if the validateConfig() function should be run. 269 * Set to false once the configuration has been validated to avoid running 270 * multiple times due to interfaces added signal. Set to true during power 271 * off to trigger the validation on power on. 272 */ 273 bool runValidateConfig = true; 274 275 /** 276 * @brief Check that all PSUs have the same model name and that the system 277 * has the required number of PSUs present as specified in the Supported 278 * Configuration interface. 279 * 280 * @param[out] additionalData - Contains debug information on why the check 281 * might have failed. Can be used to fill in error logs. 282 * @return true if all the required PSUs are present, false otherwise. 283 */ 284 bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData); 285 286 /** 287 * @brief Returns the number of PSUs that are required to be present. 288 * 289 * @return required number of PSUs, or 0 if the number could not be 290 * determined. 291 */ 292 unsigned int getRequiredPSUCount(); 293 294 /** 295 * @brief Returns whether the specified PSU is required to be present. 296 * 297 * @param[in] psu - Power supply to check 298 * @return true if PSU is required, false otherwise. 299 */ 300 bool isRequiredPSU(const PowerSupply& psu); 301 302 /** 303 * @brief Helper function to validate that all PSUs have the same model name 304 * 305 * @param[out] model - The model name. Empty if there is a mismatch. 306 * @param[out] additionalData - If there is a mismatch, it contains debug 307 * information such as the mismatched model name. 308 * @return true if all the PSUs have the same model name, false otherwise. 309 */ 310 bool validateModelName(std::string& model, 311 std::map<std::string, std::string>& additionalData); 312 313 /** 314 * @brief Set the power-config-full-load GPIO depending on the EM full load 315 * property value. 316 */ 317 void setPowerConfigGPIO(); 318 319 /** 320 * @brief Determine if system is in brownout failure 321 * @param additionalData AdditionalData property of the error log entry 322 * @return true if system is in brownout failure, false otherwise. 323 */ 324 bool isBrownout(std::map<std::string, std::string>& additionalData); 325 326 /** 327 * @brief Indicate that the system is in a brownout condition by creating an 328 * error log and setting the PowerSystemInputs status property to Fault. 329 * 330 * @param[in] additionalData - Contains debug information on the number of 331 * PSUs in fault state or not present. 332 */ 333 void setBrownout(std::map<std::string, std::string>& additionalData); 334 335 /** 336 * @brief Indicate that the system is no longer in a brownout condition by 337 * setting the PowerSystemInputs status property to Good. 338 */ 339 void clearBrownout(); 340 341 /** 342 * @brief Map of supported PSU configurations that include the model name 343 * and their properties. 344 */ 345 std::map<std::string, sys_properties> supportedConfigs; 346 347 /** 348 * @brief The vector for power supplies. 349 */ 350 std::vector<std::unique_ptr<PowerSupply>> psus; 351 352 /** 353 * @brief The libgpiod object for setting the power supply config 354 */ 355 std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr; 356 357 /** 358 * @brief PowerSystemInputs object 359 */ 360 PowerSystemInputs powerSystemInputs; 361 362 /** 363 * @brief Implement the ObjectManager for PowerSystemInputs object. 364 * 365 * Implements the org.freedesktop.DBus.ObjectManager interface used to 366 * communicate updates to the PowerSystemInputs object on the 367 * /xyz/openbmc_project/power/power_supplies root D-Bus path. 368 */ 369 sdbusplus::server::manager_t objectManager; 370 371 /** 372 * @brief Implement the ObjectManager for power supply input history. 373 * 374 * Implements the org.freedesktop.DBus.ObjectManager interface used to 375 * communicate updates to the Average and Maximum interface properties on 376 * the /org/open_power/sensors root D-Bus path. 377 */ 378 sdbusplus::server::manager_t historyManager; 379 380 /** 381 * @brief GPIO to toggle to 'sync' power supply input history. 382 */ 383 std::unique_ptr<GPIOInterfaceBase> syncHistoryGPIO = nullptr; 384 385 /** 386 * @brief Toggles the GPIO to sync power supply input history readings 387 * 388 * This GPIO is connected to all supplies. This will clear the 389 * previous readings out of the supplies and restart them both at the 390 * same time zero and at record ID 0. The supplies will return 0 391 * bytes of data for the input history command right after this until 392 * a new entry shows up. 393 * 394 * This will cause the code to delete all previous history data and 395 * start fresh. 396 */ 397 void syncHistory(); 398 }; 399 400 } // namespace phosphor::power::manager 401