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