xref: /openbmc/openpower-occ-control/powermode.hpp (revision cde7bea3d41e51204dad61761d46af70b34a787a)
1 #pragma once
2 
3 #include "config.h"
4 
5 #ifdef POWER10
6 #include "occ_command.hpp"
7 
8 #include <cereal/archives/json.hpp>
9 //#include <cereal/archives/binary.hpp>
10 #include <cereal/cereal.hpp>
11 #include <cereal/types/string.hpp>
12 #include <cereal/types/tuple.hpp>
13 #include <cereal/types/vector.hpp>
14 #include <sdbusplus/bus.hpp>
15 #include <sdbusplus/bus/match.hpp>
16 #include <xyz/openbmc_project/Control/Power/IdlePowerSaver/server.hpp>
17 #include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
18 
19 #include <filesystem>
20 
21 namespace open_power
22 {
23 namespace occ
24 {
25 
26 class Manager;
27 
28 namespace powermode
29 {
30 namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server;
31 using ModeInterface = sdbusplus::server::object::object<Base::Mode>;
32 using IpsInterface = sdbusplus::server::object::object<Base::IdlePowerSaver>;
33 using namespace std::literals::string_literals;
34 
35 constexpr auto PMODE_PATH = "/xyz/openbmc_project/control/host0/power_mode";
36 constexpr auto PMODE_INTERFACE = "xyz.openbmc_project.Control.Power.Mode";
37 constexpr auto POWER_MODE_PROP = "PowerMode";
38 
39 constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
40 constexpr auto PIPS_INTERFACE =
41     "xyz.openbmc_project.Control.Power.IdlePowerSaver";
42 constexpr auto IPS_ENABLED_PROP = "Enabled";
43 constexpr auto IPS_ENTER_UTIL = "EnterUtilizationPercent";
44 constexpr auto IPS_ENTER_TIME = "EnterDwellTime";
45 constexpr auto IPS_EXIT_UTIL = "ExitUtilizationPercent";
46 constexpr auto IPS_EXIT_TIME = "ExitDwellTime";
47 
48 const auto PMODE_DEFAULT_INTERFACE =
49     "xyz.openbmc_project.Configuration.PowerModeProperties"s;
50 
51 /** @brief Query the current Hypervisor target
52  * @return true if the current Hypervisor target is PowerVM
53  */
54 bool isPowerVM();
55 
56 /** @brief Convert power mode string to OCC SysPwrMode value
57  *
58  * @param[in] i_modeString - power mode string
59  *
60  * @return  SysPwrMode or SysPwrMode::NO_CHANGE if not found
61  */
62 SysPwrMode convertStringToMode(const std::string& i_modeString);
63 
64 struct PowerModeData
65 {
66     bool modeInitialized = false;
67     SysPwrMode mode = SysPwrMode::NO_CHANGE;
68     uint16_t oemModeData = 0x0000;
69     bool ipsInitialized = false;
70     bool ipsEnabled = true;
71     uint8_t ipsEnterUtil = 0;
72     uint16_t ipsEnterTime = 0;
73     uint8_t ipsExitUtil = 0;
74     uint16_t ipsExitTime = 0;
75 
76     /** @brief Function specifying data to archive for cereal.
77      */
78     template <class Archive>
79     void serialize(Archive& archive)
80     {
81         archive(modeInitialized, mode, oemModeData, ipsInitialized, ipsEnabled,
82                 ipsEnterUtil, ipsEnterTime, ipsExitUtil, ipsExitTime);
83     }
84 };
85 
86 /** @class OccPersistData
87  *  @brief Provides persistent container to store data for OCC
88  *
89  * Data is stored via cereal
90  */
91 class OccPersistData
92 {
93   public:
94     ~OccPersistData() = default;
95     OccPersistData(const OccPersistData&) = default;
96     OccPersistData& operator=(const OccPersistData&) = default;
97     OccPersistData(OccPersistData&&) = default;
98     OccPersistData& operator=(OccPersistData&&) = default;
99 
100     /** @brief Loads any saved power mode data */
101     OccPersistData()
102     {
103         load();
104     }
105 
106     /** @brief Save Power Mode data to persistent file
107      *
108      *  @param[in] newMode - desired System Power Mode
109      *  @param[in] oemModeData - data required by some OEM Power Modes
110      */
111     void updateMode(const SysPwrMode newMode, const uint16_t oemModeData)
112     {
113         modeData.mode = newMode;
114         modeData.oemModeData = oemModeData;
115         modeData.modeInitialized = true;
116         save();
117     }
118 
119     /** @brief Write Idle Power Saver parameters to persistent file
120      *
121      *  @param[in] enabled - Idle Power Save status (true = enabled)
122      *  @param[in] enterUtil - IPS Enter Utilization (%)
123      *  @param[in] enterTime - IPS Enter Time (seconds)
124      *  @param[in] exitUtil - IPS Exit Utilization (%)
125      *  @param[in] exitTime - IPS Exit Time (seconds)
126      */
127     void updateIPS(const bool enabled, const uint8_t enterUtil,
128                    const uint16_t enterTime, const uint8_t exitUtil,
129                    const uint16_t exitTime)
130     {
131         modeData.ipsEnabled = enabled;
132         modeData.ipsEnterUtil = enterUtil;
133         modeData.ipsEnterTime = enterTime;
134         modeData.ipsExitUtil = exitUtil;
135         modeData.ipsExitTime = exitTime;
136         modeData.ipsInitialized = true;
137         save();
138     }
139 
140     /** @brief Return the Power Mode and mode data
141      *
142      *  @param[out] mode - current system power mode
143      *  @param[out] oemModeData - frequency data for some OEM mode
144      *
145      *  @returns true if mode was available
146      */
147     bool getMode(SysPwrMode& mode, uint16_t& oemModeData) const
148     {
149         if (!modeData.modeInitialized)
150         {
151             return false;
152         }
153 
154         mode = modeData.mode;
155         oemModeData = modeData.oemModeData;
156         return true;
157     }
158 
159     /** @brief Get the Idle Power Saver properties from DBus
160      *
161      *  @param[out] enabled - Idle Power Save status (true = enabled)
162      *  @param[out] enterUtil - IPS Enter Utilization (%)
163      *  @param[out] enterTime - IPS Enter Time (seconds)
164      *  @param[out] exitUtil - IPS Exit Utilization (%)
165      *  @param[out] exitTime - IPS Exit Time (seconds)
166      *
167      * @return true if parameters were read successfully
168      */
169     bool getIPS(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
170                 uint8_t& exitUtil, uint16_t& exitTime)
171     {
172         if (!modeData.ipsInitialized)
173         {
174             return false;
175         }
176 
177         enabled = modeData.ipsEnabled;
178         enterUtil = modeData.ipsEnterUtil;
179         enterTime = modeData.ipsEnterTime;
180         exitUtil = modeData.ipsExitUtil;
181         exitTime = modeData.ipsExitTime;
182         return true;
183     }
184 
185     /** @brief Return true if the power mode is available */
186     bool modeAvailable()
187     {
188         return (modeData.modeInitialized);
189     }
190 
191     /** @brief Return true if the IPS data is available */
192     bool ipsAvailable()
193     {
194         return (modeData.ipsInitialized);
195     }
196 
197     /** @brief Saves the Power Mode data in the filesystem using cereal. */
198     void save();
199 
200     /** @brief Trace the Power Mode and IPS parameters. */
201     void print();
202 
203   private:
204     /** @brief Power Mode data filename to store persistent data */
205     static constexpr auto powerModeFilename = "powerModeData";
206 
207     /** @brief Power Mode data object to be persisted */
208     PowerModeData modeData;
209 
210     /** @brief Loads the OEM mode data in the filesystem using cereal. */
211     void load();
212 };
213 
214 /** @class PowerMode
215  *  @brief Monitors for changes to the power mode and notifies occ
216  *
217  *  The customer power mode is provided to the OCC by host TMGT when the occ
218  *  first goes active or is reset.  This code is responsible for sending
219  *  the power mode to the OCC if the mode is changed while the occ is active.
220  */
221 
222 class PowerMode : public ModeInterface, public IpsInterface
223 {
224   public:
225     /** @brief PowerMode object to inform occ of changes to mode
226      *
227      * This object will monitor for changes to the power mode setting.
228      * If a change is detected, and the occ is active, then this object will
229      * notify the OCC of the change.
230      *
231      * @param[in] managerRef - manager object reference
232      * @param[in] modePath - Power Mode dbus path
233      * @param[in] ipsPath - Idle Power Saver dbus path
234      */
235     explicit PowerMode(const Manager& managerRef, const char* modePath,
236                        const char* ipsPath) :
237         ModeInterface(utils::getBus(), modePath, false),
238         IpsInterface(utils::getBus(), ipsPath, false), manager(managerRef),
239         pmodeMatch(utils::getBus(),
240                    sdbusplus::bus::match::rules::propertiesChanged(
241                        PMODE_PATH, PMODE_INTERFACE),
242                    [this](auto& msg) { this->modeChanged(msg); }),
243         ipsMatch(utils::getBus(),
244                  sdbusplus::bus::match::rules::propertiesChanged(
245                      PIPS_PATH, PIPS_INTERFACE),
246                  [this](auto& msg) { this->ipsChanged(msg); }),
247         defaultsUpdateMatch(
248             utils::getBus(),
249             sdbusplus::bus::match::rules::propertiesChangedNamespace(
250                 "/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE),
251             [this](auto& msg) { this->defaultsReady(msg); }),
252         masterOccSet(false), masterActive(false)
253     {
254         // restore Power Mode to DBus
255         SysPwrMode currentMode;
256         uint16_t oemModeData = 0;
257         if (getMode(currentMode, oemModeData))
258         {
259             updateDbusMode(currentMode);
260         }
261         // restore Idle Power Saver parameters to DBus
262         uint8_t enterUtil, exitUtil;
263         uint16_t enterTime, exitTime;
264         bool ipsEnabled;
265         if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime))
266         {
267             updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
268         }
269     };
270 
271     /** @brief Initialize the persistent data with default values
272      *
273      * @return true if initialization completed
274      */
275     bool initPersistentData();
276 
277     /** @brief Set the current power mode property
278      *
279      * @param[in] newMode     - desired system power mode
280      * @param[in] oemModeData - data required by some OEM Power Modes
281      *
282      * @return true if mode accepted
283      */
284     bool setMode(const SysPwrMode newMode, const uint16_t oemModeData);
285 
286     /** @brief Send mode change command to the master OCC
287      *  @return SUCCESS on success
288      */
289     CmdStatus sendModeChange();
290 
291     /** @brief Send Idle Power Saver config data to the master OCC
292      *  @return SUCCESS on success
293      */
294     CmdStatus sendIpsData();
295 
296     /** @brief Set the master OCC path
297      *
298      * @param[in]  occPath - hwmon path for master OCC
299      */
300     void setMasterOcc(const std::string& occPath);
301 
302     /** @brief Notify object of master OCC state.  If not acitve, no
303      * commands will be sent to the master OCC
304      *
305      * @param[in]  isActive - true when master OCC is active
306      */
307     void setMasterActive(const bool isActive = true)
308     {
309         masterActive = isActive;
310     };
311 
312   private:
313     /** @brief OCC manager object */
314     const Manager& manager;
315 
316     /** @brief Pass-through occ path on the bus */
317     std::string path;
318 
319     /** @brief OCC instance number */
320     int occInstance;
321 
322     /** @brief Object to send commands to the OCC */
323     std::unique_ptr<open_power::occ::OccCommand> occCmd;
324 
325     /** @brief Used to subscribe to dbus pmode property changes **/
326     sdbusplus::bus::match_t pmodeMatch;
327 
328     /** @brief Used to subscribe to dbus IPS property changes **/
329     sdbusplus::bus::match_t ipsMatch;
330 
331     /** @brief Used to subscribe to dbus defaults property changes **/
332     sdbusplus::bus::match_t defaultsUpdateMatch;
333 
334     OccPersistData persistedData;
335 
336     /** @brief True when the master OCC has been established */
337     bool masterOccSet;
338 
339     /** @brief True when the master OCC is active */
340     bool masterActive;
341 
342     /** @brief Callback for pmode setting changes
343      *
344      * Process change and inform OCC
345      *
346      * @param[in]  msg       - Data associated with pmode change signal
347      *
348      */
349     void modeChanged(sdbusplus::message::message& msg);
350 
351     /** @brief Get the current power mode property
352      *
353      * @param[out] currentMode - current system power mode
354      * @param[out] oemModeData - frequency data for some OEM mode
355      *
356      * @return true if data read successfully
357      */
358     bool getMode(SysPwrMode& currentMode, uint16_t& oemModeData);
359 
360     /** @brief Update the power mode property on DBus
361      *
362      * @param[in]  newMode - desired power mode
363      *
364      * @return true on success
365      */
366     bool updateDbusMode(const SysPwrMode newMode);
367 
368     /** @brief Callback for IPS setting changes
369      *
370      * Process change and inform OCC
371      *
372      * @param[in]  msg - Data associated with IPS change signal
373      *
374      */
375     void ipsChanged(sdbusplus::message::message& msg);
376 
377     /** @brief Get the Idle Power Saver properties
378      *
379      *  @param[out] enabled - Idle Power Save status (true = enabled)
380      *  @param[out] enterUtil - IPS Enter Utilization (%)
381      *  @param[out] enterTime - IPS Enter Time (seconds)
382      *  @param[out] exitUtil - IPS Exit Utilization (%)
383      *  @param[out] exitTime - IPS Exit Time (seconds)
384      *
385      * @return true if data read successfully
386      */
387     bool getIPSParms(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
388                      uint8_t& exitUtil, uint16_t& exitTime);
389 
390     /** Update the Idle Power Saver data on DBus
391      *
392      *  @param[in] enabled - Idle Power Save status (true = enabled)
393      *  @param[in] enterUtil - IPS Enter Utilization (%)
394      *  @param[in] enterTime - IPS Enter Time (seconds)
395      *  @param[in] exitUtil - IPS Exit Utilization (%)
396      *  @param[in] exitTime - IPS Exit Time (seconds)
397      *
398      *  @return true if parameters were set successfully
399      */
400     bool updateDbusIPS(const bool enabled, const uint8_t enterUtil,
401                        const uint16_t enterTime, const uint8_t exitUtil,
402                        const uint16_t exitTime);
403 
404     /** @brief Callback for entity manager default changes
405      *
406      * Called when PowerModeProperties defaults are available
407      */
408     void defaultsReady(sdbusplus::message::message& msg);
409 
410     /** @brief Get the default power mode property for this system type
411      *
412      * @param[out] defaultMode - default system power mode
413      *
414      * @return true if data read successfully
415      */
416     bool getDefaultMode(SysPwrMode& defaultMode);
417 
418     /** @brief Get the default Idle Power Saver properties for this system type
419      *
420      *  @param[out] enabled - Idle Power Save status (true = enabled)
421      *  @param[out] enterUtil - IPS Enter Utilization (%)
422      *  @param[out] enterTime - IPS Enter Time (seconds)
423      *  @param[out] exitUtil - IPS Exit Utilization (%)
424      *  @param[out] exitTime - IPS Exit Time (seconds)
425      *
426      *  @return true if parameters were read successfully
427      */
428     bool getDefaultIPSParms(bool& enabled, uint8_t& enterUtil,
429                             uint16_t& enterTime, uint8_t& exitUtil,
430                             uint16_t& exitTime);
431 
432     /** @brief Read the default Idle Power Saver parameters and save them to the
433      * DBUS so they will get used
434      *
435      * @return true if restore was successful
436      */
437     bool useDefaultIPSParms();
438 };
439 
440 } // namespace powermode
441 
442 } // namespace occ
443 
444 } // namespace open_power
445 #endif
446