xref: /openbmc/phosphor-power/phosphor-power-supply/chassis.hpp (revision b7878e55662bafbf28581c5b3b677207195fb8b3)
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] chassisName - Chassis name
80      * @param[in] event - Event loop object
81      */
82     Chassis(sdbusplus::bus_t& bus, const std::string& chassisPath,
83             const std::string& chassisName, const sdeventplus::Event& e);
84 
85     /**
86      * @brief Retrieves the unique identifier of the chassis.
87      *
88      * @return uint64_t The unique 64 bits identifier of the chassis.
89      */
getChassisId()90     uint64_t getChassisId()
91     {
92         return chassisPathUniqueId;
93     }
94 
95     /**
96      * @brief Analyze the status of each of the power supplies. Log errors for
97      * faults, when and where appropriate.
98      */
99     void analyze();
100 
101     /**
102      * @brief Get the status of Power on.
103      */
isPowerOn()104     bool isPowerOn()
105     {
106         return powerOn;
107     }
108 
109     /**
110      * @brief Initialize power monitoring infrastructure for Chassis.
111      * Sets up configuration validation timer, attempts to create GPIO,
112      * subscribe to D-Bus power state change events.
113      */
114     void initPowerMonitoring();
115 
116     /**
117      * @brief Handles addition of the SupportedConfiguration interface.
118      * This function triggered when the SupportedConfiguration interface added
119      * to a D-Bus object. The function  calls populateSupportedConfiguration()
120      * and updateMissingPSUs() to processes the provided properties.
121      *
122      * @param properties A map of D-Bus properties associated with the
123      * SupportedConfiguration interface.
124      */
125     void supportedConfigurationInterfaceAdded(
126         const util::DbusPropertyMap& properties);
127 
128     /**
129      * @brief Handle the addition of PSU interface.
130      * This function is called when a Power Supply interface added to a D-Bus.
131      * This function calls getPSUProperties() and updateMissingPSUs().
132      *
133      * @param properties A map of D-Bus properties for the PSU interface.
134      */
135     void psuInterfaceAdded(util::DbusPropertyMap& properties);
136 
137     /**
138      * @brief Call to validate the psu configuration if the power is on and both
139      * the IBMCFFPSConnector and SupportedConfiguration interfaces have been
140      * processed
141      */
validatePsuConfigAndInterfacesProcessed()142     void validatePsuConfigAndInterfacesProcessed()
143     {
144         if (powerOn && !psus.empty() && !supportedConfigs.empty())
145         {
146             validationTimer->restartOnce(validationTimeout);
147         }
148     };
149 
150   private:
151     /**
152      * @brief The D-Bus object
153      */
154     sdbusplus::bus_t& bus;
155 
156     /**
157      * @brief The timer that performs power supply validation as the entity
158      * manager interfaces show up in d-bus.
159      */
160     std::unique_ptr<
161         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
162         validationTimer;
163 
164     /** @brief True if the power is on. */
165     bool powerOn = false;
166 
167     /** @brief True if power control is in the window between chassis pgood loss
168      * and power off.
169      */
170     bool powerFaultOccurring = false;
171 
172     /** @brief True if an error for a brownout has already been logged. */
173     bool brownoutLogged = false;
174 
175     /** @brief Used as part of subscribing to power on state changes*/
176     std::string powerService;
177 
178     /** @brief Used to subscribe to D-Bus power on state changes */
179     std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
180 
181     /** @brief Used to subscribe to D-Bus power supply presence changes */
182     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> presenceMatches;
183 
184     /**
185      * @brief Flag to indicate if the validateConfig() function should be run.
186      * Set to false once the configuration has been validated to avoid
187      * running multiple times due to interfaces added signal. Set to
188      * true during power off to trigger the validation on power on.
189      */
190     bool runValidateConfig = true;
191 
192     /**
193      * @brief Map of supported PSU configurations that include the model name
194      * and their properties.
195      */
196     std::map<std::string, SupportedPsuConfiguration> supportedConfigs;
197 
198     /**
199      * @brief The vector for power supplies.
200      */
201     std::vector<std::unique_ptr<PowerSupply>> psus;
202 
203     /**
204      * @brief The device driver name for all power supplies.
205      */
206     std::string driverName;
207 
208     /**
209      * @brief The libgpiod object for setting the power supply config
210      */
211     std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr;
212 
213     /**
214      * @brief Chassis D-Bus object path
215      */
216     std::string chassisPath;
217 
218     /**
219      * @brief Chassis name;
220      */
221     std::string chassisShortName;
222 
223     /**
224      * @brief The Chassis path unique ID
225      *
226      * Note: chassisPathUniqueId must be declared before powerSystemInputs.
227      */
228     uint64_t chassisPathUniqueId = invalidObjectPathUniqueId;
229 
230     /**
231      * @brief PowerSystemInputs object
232      */
233     PowerSystemInputs powerSystemInputs;
234 
235     /**
236      * @brief ObjectManager path
237      */
238     std::string objectManagerPath;
239 
240     /**
241      * @brief Implement the objectManager for PowerSystemInputs object.
242      *
243      * Implements the org.freedesktop.DBus.ObjectManager interface used to
244      * communicate updates to the PowerSystemInputs object on the
245      * /xyz/openbmc_project/power/power_supplies/{}/psus (where {} is
246      * replaced with chassisX) root D-Bus path.
247      */
248     sdbusplus::server::manager_t objectManager;
249 
250     /**
251      * @brief Implement the ObjectManager for the input voltage rating.
252      *
253      * Implements the org.freedesktop.DBus.ObjectManager interface used to
254      * communicate updates to the input voltage ratings on the
255      * /xyz/openbmc_project/sensors root D-Bus path.
256      */
257     sdbusplus::server::manager_t sensorsObjManager;
258 
259     /**
260      * @brief Declares a constant reference to an sdeventplus::Event to manage
261      * async processing.
262      */
263     const sdeventplus::Event& eventLoop;
264 
265     /**
266      * @brief GPIO to toggle to 'sync' power supply input history.
267      */
268     std::unique_ptr<GPIOInterfaceBase> syncHistoryGPIO = nullptr;
269 
270     /**
271      * @brief Get PSU properties from D-Bus, use that to build a power supply
272      * object.
273      *
274      * @param[in] properties - A map of property names and values
275      */
276     void getPSUProperties(util::DbusPropertyMap& properties);
277 
278     /**
279      * @brief Get PSU configuration from D-Bus
280      */
281     void getPSUConfiguration();
282 
283     /**
284      * @brief Queries D-Bus for chassis configuration provided by the Entity
285      * Manager. Matches the object against the current chassis unique ID. Upon
286      * finding a match calls populateSupportedConfiguration().
287      */
288     void getSupportedConfiguration();
289 
290     /**
291      * @brief Callback for inventory property changes
292      *
293      * Process change of the Power Supply presence.
294      *
295      * @param[in]  msg - Data associated with the Present change signal
296      **/
297     void psuPresenceChanged(sdbusplus::message_t& msg);
298 
299     /**
300      * @brief Helper function to populate the PSU supported configuration
301      *
302      * @param[in] properties - A map of property names and values
303      */
304     void populateSupportedConfiguration(
305         const util::DbusPropertyMap& properties);
306 
307     /**
308      * @brief Build the device driver name for the power supply.
309      *
310      * @param[in] i2cbus - i2c bus
311      * @param[in] i2caddr - i2c bus address
312      */
313     void buildDriverName(uint64_t i2cbus, uint64_t i2caddr);
314 
315     /**
316      * @brief Find PSU with device driver name, then populate the device
317      * driver name to all PSUs (including missing PSUs).
318      */
319     void populateDriverName();
320 
321     /**
322      * @brief Get chassis path unique ID.
323      *
324      * @param [in] path - Chassis path.
325      * @return uint64_t - Chassis path unique ID.
326      */
327     uint64_t getChassisPathUniqueId(const std::string& path);
328 
329     /**
330      * @brief Initializes the chassis.
331      *
332      */
333     void initialize();
334 
335     /**
336      * @brief Perform power supply configuration validation.
337      * @details Validates if the existing power supply properties are a
338      * supported configuration, and acts on its findings such as logging
339      * errors.
340      */
341     void validateConfig();
342 
343     /**
344      * @brief Analyze the set of the power supplies for a brownout failure. Log
345      * error when necessary, clear brownout condition when window has passed.
346      */
347     void analyzeBrownout();
348 
349     /**
350      * @brief Toggles the GPIO to sync power supply input history readings
351      * @details This GPIO is connected to all supplies.  This will clear the
352      * previous readings out of the supplies and restart them both at the
353      * same time zero and at record ID 0.  The supplies will return 0
354      * bytes of data for the input history command right after this until
355      * a new entry shows up.
356      *
357      * This will cause the code to delete all previous history data and
358      * start fresh.
359      */
360     void syncHistory();
361 
362     /**
363      * @brief Tells each PSU to set its power supply input
364      * voltage rating D-Bus property.
365      */
setInputVoltageRating()366     inline void setInputVoltageRating()
367     {
368         for (auto& psu : psus)
369         {
370             psu->setInputVoltageRating();
371         }
372     }
373 
374     /**
375      * Create an error
376      *
377      * @param[in] faultName - 'name' message for the BMC error log entry
378      * @param[in,out] additionalData - The AdditionalData property for the error
379      */
380     void createError(const std::string& faultName,
381                      std::map<std::string, std::string>& additionalData);
382 
383     /**
384      * @brief Check that all PSUs have the same model name and that the system
385      * has the required number of PSUs present as specified in the Supported
386      * Configuration interface.
387      *
388      * @param[out] additionalData - Contains debug information on why the check
389      *             might have failed. Can be used to fill in error logs.
390      * @return true if all the required PSUs are present, false otherwise.
391      */
392     bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData);
393 
394     /**
395      * @brief Update inventory for missing required power supplies
396      */
397     void updateMissingPSUs();
398 
399     /**
400      * @brief Callback for power state property changes
401      *
402      * Process changes to the powered on state property for the chassis.
403      *
404      * @param[in] msg - Data associated with the power state signal
405      */
406     void powerStateChanged(sdbusplus::message_t& msg);
407 
408     /**
409      * @breif Attempt to create GPIO
410      */
411     void attemptToCreatePowerConfigGPIO();
412 
413     /**
414      * Write PMBus ON_OFF_CONFIG
415      *
416      * This function will be called to cause the PMBus device driver to send the
417      * ON_OFF_CONFIG command. Takes one byte of data.
418      */
onOffConfig(const uint8_t data)419     void onOffConfig(const uint8_t data)
420     {
421         for (auto& psu : psus)
422         {
423             psu->onOffConfig(data);
424         }
425     }
426 
427     /**
428      * This function will be called in various situations in order to clear
429      * any fault status bits that may have been set, in order to start over
430      * with a clean state. Presence changes and power state changes will want
431      * to clear any faults logged.
432      */
clearFaults()433     void clearFaults()
434     {
435         setPowerSupplyError("");
436         for (auto& psu : psus)
437         {
438             psu->clearFaults();
439         }
440     }
441 
442     /**
443      * Let power control/sequencer application know of PSU error(s).
444      *
445      * @param[in] psuErrorString - string for power supply error
446      */
447     void setPowerSupplyError(const std::string& psuErrorString);
448 
449     /**
450      * @brief Set the power-config-full-load GPIO depending on the EM full load
451      *        property value.
452      */
453     void setPowerConfigGPIO();
454 
455     /**
456      * @brief Helper function to validate that all PSUs have the same model name
457      *
458      * @param[out] model - The model name. Empty if there is a mismatch.
459      * @param[out] additionalData - If there is a mismatch, it contains debug
460      *             information such as the mismatched model name.
461      * @return true if all the PSUs have the same model name, false otherwise.
462      */
463     bool validateModelName(std::string& model,
464                            std::map<std::string, std::string>& additionalData);
465 
466     /**
467      * @brief Returns the number of PSUs that are required to be present.
468      *
469      * @return required number of PSUs, or 0 if the number could not be
470      *         determined.
471      */
472     unsigned int getRequiredPSUCount();
473 
474     /**
475      * @brief Returns whether the specified PSU is required to be present.
476      *
477      * @param[in] psu - Power supply to check
478      * @return true if PSU is required, false otherwise.
479      */
480     bool isRequiredPSU(const PowerSupply& psu);
481 };
482 
483 } // namespace phosphor::power::chassis
484