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