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 <sdeventplus/event.hpp>
10 #include <sdeventplus/utility/timer.hpp>
11 
12 struct sys_properties
13 {
14     int powerSupplyCount;
15     std::vector<uint64_t> inputVoltage;
16     bool powerConfigFullLoad;
17 };
18 
19 using namespace phosphor::power::psu;
20 using namespace phosphor::logging;
21 
22 namespace phosphor::power::manager
23 {
24 
25 // Validation timeout. Allow 10s to detect if new EM interfaces show up in D-Bus
26 // before performing the validation.
27 constexpr auto validationTimeout = std::chrono::seconds(10);
28 
29 /**
30  * @class PSUManager
31  *
32  * This class will create an object used to manage and monitor a list of power
33  * supply devices.
34  */
35 class PSUManager
36 {
37   public:
38     PSUManager() = delete;
39     ~PSUManager() = default;
40     PSUManager(const PSUManager&) = delete;
41     PSUManager& operator=(const PSUManager&) = delete;
42     PSUManager(PSUManager&&) = delete;
43     PSUManager& operator=(PSUManager&&) = delete;
44 
45     /**
46      * Constructor to read configuration from D-Bus.
47      *
48      * @param[in] bus - D-Bus bus object
49      * @param[in] e - event object
50      */
51     PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e);
52 
53     /**
54      * Get PSU properties from D-Bus, use that to build a power supply
55      * object.
56      *
57      * @param[in] properties - A map of property names and values
58      *
59      */
60     void getPSUProperties(util::DbusPropertyMap& properties);
61 
62     /**
63      * Get PSU configuration from D-Bus
64      */
65     void getPSUConfiguration();
66 
67     /**
68      * @brief Initialize the system properties from the Supported Configuration
69      *        D-Bus object provided by Entity Manager.
70      */
71     void getSystemProperties();
72 
73     /**
74      * Initializes the manager.
75      *
76      * Get current BMC state, ...
77      */
78     void initialize()
79     {
80         // When state = 1, system is powered on
81         int32_t state = 0;
82 
83         try
84         {
85             // Use getProperty utility function to get power state.
86             util::getProperty<int32_t>(POWER_IFACE, "state", POWER_OBJ_PATH,
87                                        powerService, bus, state);
88 
89             if (state)
90             {
91                 powerOn = true;
92                 validationTimer->restartOnce(validationTimeout);
93             }
94             else
95             {
96                 powerOn = false;
97                 runValidateConfig = true;
98             }
99         }
100         catch (const std::exception& e)
101         {
102             log<level::INFO>("Failed to get power state. Assuming it is off.");
103             powerOn = false;
104             runValidateConfig = true;
105         }
106 
107         onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
108         clearFaults();
109         updateInventory();
110         setPowerConfigGPIO();
111     }
112 
113     /**
114      * Starts the timer to start monitoring the list of devices.
115      */
116     int run()
117     {
118         return timer->get_event().loop();
119     }
120 
121     /**
122      * Write PMBus ON_OFF_CONFIG
123      *
124      * This function will be called to cause the PMBus device driver to send the
125      * ON_OFF_CONFIG command. Takes one byte of data.
126      */
127     void onOffConfig(const uint8_t data)
128     {
129         for (auto& psu : psus)
130         {
131             psu->onOffConfig(data);
132         }
133     }
134 
135     /**
136      * This function will be called in various situations in order to clear
137      * any fault status bits that may have been set, in order to start over
138      * with a clean state. Presence changes and power state changes will want
139      * to clear any faults logged.
140      */
141     void clearFaults()
142     {
143         for (auto& psu : psus)
144         {
145             psu->clearFaults();
146         }
147     }
148 
149   private:
150     /**
151      * The D-Bus object
152      */
153     sdbusplus::bus::bus& bus;
154 
155     /**
156      * The timer that runs to periodically check the power supplies.
157      */
158     std::unique_ptr<
159         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
160         timer;
161 
162     /**
163      * The timer that performs power supply validation as the entity manager
164      * interfaces show up in d-bus.
165      */
166     std::unique_ptr<
167         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
168         validationTimer;
169 
170     /**
171      * Create an error
172      *
173      * @param[in] faultName - 'name' message for the BMC error log entry
174      * @param[in,out] additionalData - The AdditionalData property for the error
175      */
176     void createError(const std::string& faultName,
177                      std::map<std::string, std::string>& additionalData);
178 
179     /**
180      * Analyze the status of each of the power supplies.
181      *
182      * Log errors for faults, when and where appropriate.
183      */
184     void analyze();
185 
186     /** @brief True if the power is on. */
187     bool powerOn = false;
188 
189     /** @brief Used as part of subscribing to power on state changes*/
190     std::string powerService;
191 
192     /** @brief Used to subscribe to D-Bus power on state changes */
193     std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
194 
195     /** @brief Used to subscribe to Entity Manager interfaces added */
196     std::unique_ptr<sdbusplus::bus::match_t> entityManagerIfacesAddedMatch;
197 
198     /**
199      * @brief Callback for power state property changes
200      *
201      * Process changes to the powered on state property for the system.
202      *
203      * @param[in] msg - Data associated with the power state signal
204      */
205     void powerStateChanged(sdbusplus::message::message& msg);
206 
207     /**
208      * @brief Callback for entity-manager interface added
209      *
210      * Process the information from the supported configuration and or IBM CFFPS
211      * Connector interface being added.
212      *
213      * @param[in] msg - Data associated with the interfaces added signal
214      */
215     void entityManagerIfaceAdded(sdbusplus::message::message& msg);
216 
217     /**
218      * @brief Adds properties to the inventory.
219      *
220      * Reads the values from the devices and writes them to the associated
221      * power supply D-Bus inventory objects.
222      *
223      * This needs to be done on startup, and each time the presence state
224      * changes.
225      */
226     void updateInventory()
227     {
228         for (auto& psu : psus)
229         {
230             psu->updateInventory();
231         }
232     }
233 
234     /**
235      * @brief Helper function to populate the system properties
236      *
237      * @param[in] properties - A map of property names and values
238      */
239     void populateSysProperties(const util::DbusPropertyMap& properties);
240 
241     /**
242      * @brief Perform power supply configuration validation.
243      * @details Validates if the existing power supply properties are a
244      * supported configuration, and acts on its findings such as logging errors.
245      */
246     void validateConfig();
247 
248     /**
249      * @brief Flag to indicate if the validateConfig() function should be run.
250      * Set to false once the configuration has been validated to avoid running
251      * multiple times due to interfaces added signal. Set to true during power
252      * off to trigger the validation on power on.
253      */
254     bool runValidateConfig = true;
255 
256     /**
257      * @brief Check that all PSUs have the same model name and that the system
258      * has the required number of PSUs present as specified in the Supported
259      * Configuration interface.
260      *
261      * @param[out] additionalData - Contains debug information on why the check
262      *             might have failed. Can be used to fill in error logs.
263      * @return true if all the required PSUs are present, false otherwise.
264      */
265     bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData);
266 
267     /**
268      * @brief Helper function to validate that all PSUs have the same model name
269      *
270      * @param[out] model - The model name. Empty if there is a mismatch.
271      * @param[out] additionalData - If there is a mismatch, it contains debug
272      *             information such as the mismatched model name.
273      * @return true if all the PSUs have the same model name, false otherwise.
274      */
275     bool validateModelName(std::string& model,
276                            std::map<std::string, std::string>& additionalData);
277 
278     /**
279      * @brief Set the power-config-full-load GPIO depending on the EM full load
280      *        property value.
281      */
282     void setPowerConfigGPIO();
283 
284     /**
285      * @brief Map of supported PSU configurations that include the model name
286      * and their properties.
287      */
288     std::map<std::string, sys_properties> supportedConfigs;
289 
290     /**
291      * @brief The vector for power supplies.
292      */
293     std::vector<std::unique_ptr<PowerSupply>> psus;
294 
295     /**
296      * @brief The libgpiod object for setting the power supply config
297      */
298     std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr;
299 };
300 
301 } // namespace phosphor::power::manager
302