xref: /openbmc/phosphor-power/phosphor-power-supply/psu_manager.hpp (revision 0a2b76bc3031c324879c698865d1490f5b6d8b99)
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