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