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