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