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