xref: /openbmc/openpower-occ-control/powermode.hpp (revision 16a5adb204d261be727c67c4ea3b64a0965303e0)
1 #pragma once
2 
3 #include "config.h"
4 
5 #include "occ_command.hpp"
6 
7 #include <cereal/archives/json.hpp>
8 #include <cereal/cereal.hpp>
9 #include <cereal/types/string.hpp>
10 #include <cereal/types/tuple.hpp>
11 #include <cereal/types/vector.hpp>
12 #include <sdbusplus/bus.hpp>
13 #include <sdbusplus/bus/match.hpp>
14 #include <xyz/openbmc_project/Control/Power/IdlePowerSaver/server.hpp>
15 #include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
16 
17 #include <filesystem>
18 
19 namespace open_power
20 {
21 namespace occ
22 {
23 
24 class Manager;
25 
26 namespace powermode
27 {
28 namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server;
29 using ModeInterface = sdbusplus::server::object_t<Base::Mode>;
30 using IpsInterface = sdbusplus::server::object_t<Base::IdlePowerSaver>;
31 using namespace std::literals::string_literals;
32 
33 constexpr auto PMODE_PATH = "/xyz/openbmc_project/control/host0/power_mode";
34 constexpr auto PMODE_INTERFACE = "xyz.openbmc_project.Control.Power.Mode";
35 constexpr auto POWER_MODE_PROP = "PowerMode";
36 constexpr auto POWER_SAFE_MODE_PROP = "SafeMode";
37 
38 constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
39 constexpr auto PIPS_INTERFACE =
40     "xyz.openbmc_project.Control.Power.IdlePowerSaver";
41 constexpr auto IPS_ACTIVE_PROP = "Active";
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     bool modeLocked = false;
76 
77     /** @brief Function specifying data to archive for cereal.
78      */
79     template <class Archive>
serializeopen_power::occ::powermode::PowerModeData80     void serialize(Archive& archive)
81     {
82         archive(modeInitialized, mode, oemModeData, ipsInitialized, ipsEnabled,
83                 ipsEnterUtil, ipsEnterTime, ipsExitUtil, ipsExitTime,
84                 modeLocked);
85     }
86 };
87 
88 /** @class OccPersistData
89  *  @brief Provides persistent container to store data for OCC
90  *
91  * Data is stored via cereal
92  */
93 class OccPersistData
94 {
95   public:
96     ~OccPersistData() = default;
97     OccPersistData(const OccPersistData&) = default;
98     OccPersistData& operator=(const OccPersistData&) = default;
99     OccPersistData(OccPersistData&&) = default;
100     OccPersistData& operator=(OccPersistData&&) = default;
101 
102     /** @brief Loads any saved power mode data */
OccPersistData()103     OccPersistData()
104     {
105         load();
106     }
107 
108     /** @brief Save Power Mode data to persistent file
109      *
110      *  @param[in] newMode - desired System Power Mode
111      *  @param[in] oemModeData - data required by some OEM Power Modes
112      */
updateMode(const SysPwrMode newMode,const uint16_t oemModeData)113     void updateMode(const SysPwrMode newMode, const uint16_t oemModeData)
114     {
115         modeData.mode = newMode;
116         modeData.oemModeData = oemModeData;
117         modeData.modeInitialized = true;
118         save();
119     }
120 
121     /** @brief Save Power Mode Lock value to persistent file
122      *
123      *  @param[in] modeLock - desired System Power Mode Lock
124      */
updateModeLock(const bool modeLock)125     void updateModeLock(const bool modeLock)
126     {
127         modeData.modeLocked = modeLock;
128         save();
129     }
130     /** @brief Write Idle Power Saver parameters to persistent file
131      *
132      *  @param[in] enabled - Idle Power Save status (true = enabled)
133      *  @param[in] enterUtil - IPS Enter Utilization (%)
134      *  @param[in] enterTime - IPS Enter Time (seconds)
135      *  @param[in] exitUtil - IPS Exit Utilization (%)
136      *  @param[in] exitTime - IPS Exit Time (seconds)
137      */
updateIPS(const bool enabled,const uint8_t enterUtil,const uint16_t enterTime,const uint8_t exitUtil,const uint16_t exitTime)138     void updateIPS(const bool enabled, const uint8_t enterUtil,
139                    const uint16_t enterTime, const uint8_t exitUtil,
140                    const uint16_t exitTime)
141     {
142         modeData.ipsEnabled = enabled;
143         modeData.ipsEnterUtil = enterUtil;
144         modeData.ipsEnterTime = enterTime;
145         modeData.ipsExitUtil = exitUtil;
146         modeData.ipsExitTime = exitTime;
147         modeData.ipsInitialized = true;
148         save();
149     }
150 
151     /** @brief Return the Power Mode and mode data
152      *
153      *  @param[out] mode - current system power mode
154      *  @param[out] oemModeData - frequency data for some OEM mode
155      *
156      *  @returns true if mode was available
157      */
getMode(SysPwrMode & mode,uint16_t & oemModeData) const158     bool getMode(SysPwrMode& mode, uint16_t& oemModeData) const
159     {
160         if (modeData.modeInitialized)
161         {
162             mode = modeData.mode;
163             oemModeData = modeData.oemModeData;
164         }
165         return modeData.modeInitialized;
166     }
167 
168     /** @brief Get the Idle Power Saver properties from DBus
169      *
170      *  @param[out] enabled - Idle Power Save status (true = enabled)
171      *  @param[out] enterUtil - IPS Enter Utilization (%)
172      *  @param[out] enterTime - IPS Enter Time (seconds)
173      *  @param[out] exitUtil - IPS Exit Utilization (%)
174      *  @param[out] exitTime - IPS Exit Time (seconds)
175      *
176      * @return true if parameters were read successfully
177      */
getIPS(bool & enabled,uint8_t & enterUtil,uint16_t & enterTime,uint8_t & exitUtil,uint16_t & exitTime)178     bool getIPS(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
179                 uint8_t& exitUtil, uint16_t& exitTime)
180     {
181         if (!modeData.ipsInitialized)
182         {
183             return false;
184         }
185 
186         enabled = modeData.ipsEnabled;
187         enterUtil = modeData.ipsEnterUtil;
188         enterTime = modeData.ipsEnterTime;
189         exitUtil = modeData.ipsExitUtil;
190         exitTime = modeData.ipsExitTime;
191         return true;
192     }
193 
194     /** @brief Return persisted mode lock */
getModeLock()195     bool getModeLock()
196     {
197         return modeData.modeLocked;
198     }
199 
200     /** @brief Return true if the power mode is available */
modeAvailable()201     bool modeAvailable()
202     {
203         return (modeData.modeInitialized);
204     }
205 
206     /** @brief Return true if the IPS data is available */
ipsAvailable()207     bool ipsAvailable()
208     {
209         return (modeData.ipsInitialized);
210     }
211 
212     /** @brief Saves the Power Mode data in the filesystem using cereal. */
213     void save();
214 
215     /** @brief Trace the Power Mode and IPS parameters. */
216     void print();
217 
218     /** @brief Invalidate the persisted mode */
invalidateMode()219     void invalidateMode()
220     {
221         modeData.modeInitialized = false;
222     }
223 
224   private:
225     /** @brief Power Mode data filename to store persistent data */
226     static constexpr auto powerModeFilename = "powerModeData";
227 
228     /** @brief Power Mode data object to be persisted */
229     PowerModeData modeData;
230 
231     /** @brief Loads the OEM mode data in the filesystem using cereal. */
232     void load();
233 };
234 
235 /** @class PowerMode
236  *  @brief Monitors for changes to the power mode and notifies occ
237  *
238  *  The customer power mode is provided to the OCC by host TMGT when the occ
239  *  first goes active or is reset.  This code is responsible for sending
240  *  the power mode to the OCC if the mode is changed while the occ is active.
241  */
242 
243 class PowerMode : public ModeInterface
244 {
245   public:
246     /** @brief PowerMode object to inform occ of changes to mode
247      *
248      * This object will monitor for changes to the power mode setting.
249      * If a change is detected, and the occ is active, then this object will
250      * notify the OCC of the change.
251      *
252      * @param[in] managerRef - manager object reference
253      * @param[in] modePath - Power Mode dbus path
254      * @param[in] ipsPath - Idle Power Saver dbus path
255      */
256     explicit PowerMode(const Manager& managerRef, const char* modePath,
257                        const char* ipsPath, EventPtr& event);
258 
259     /** @brief Initialize the persistent data with default values
260      *
261      * @return true if initialization completed
262      */
263     bool initPersistentData();
264 
265     /** @brief Set the power mode lock (dbus method)
266      *
267      * @return true if successful
268      */
269     bool powerModeLock();
270 
271     /** @brief Get the power mode lock status (dbus method)
272      *
273      * @return true if locked
274      */
275     bool powerModeLockStatus();
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      */
setMasterActive(const bool isActive=true)307     void setMasterActive(const bool isActive = true)
308     {
309         masterActive = isActive;
310     };
311 
312     /** @brief Starts to monitor for IPS active state change conditions
313      *
314      *  @param[in] poll - Indicates whether or not the IPS state file should
315      *                    actually be read for changes.
316      */
317     void addIpsWatch(bool poll = true);
318 
319     /** @brief Removes IPS active watch */
320     void removeIpsWatch();
321 
322     /** @brief Set dbus property to SAFE Mode(true) or clear SAFE Mode(false)*/
323     void updateDbusSafeMode(const bool safeMode);
324 
325     /** @brief override the set/get MODE function
326      *
327      *  @param[in] value - Intended value
328      *
329      *  @return          - the value or Updated value of the property
330      */
331     Base::Mode::PowerMode powerMode(Base::Mode::PowerMode value) override;
332 
333     /** @brief Determine if the supplied mode is valid for the system
334      *
335      *  @param[in] mode  - potential mode
336      *
337      *  @return          - true if the mode is valid
338      */
339     bool isValidMode(const SysPwrMode mode);
340 
341     /** @brief If IPS is supported, set flag indicating need to send IPS data */
needToSendIPS()342     void needToSendIPS()
343     {
344         if (ipsObject)
345         {
346             needToSendIpsData = true;
347         }
348     }
349 
350   private:
351     /** @brief OCC manager object */
352     const Manager& manager;
353 
354     /** @brief Pass-through occ path on the bus */
355     std::string path;
356 
357     /** @brief OCC instance number */
358     int occInstance;
359 
360     /** @brief Object to send commands to the OCC */
361     std::unique_ptr<open_power::occ::OccCommand> occCmd;
362 
363     /** @brief Used to subscribe to dbus IPS property changes **/
364     sdbusplus::bus::match_t ipsMatch;
365 
366     /** @brief Used to subscribe to dbus defaults property changes **/
367     sdbusplus::bus::match_t defaultsUpdateMatch;
368 
369     OccPersistData persistedData;
370 
371     /** @brief True when the master OCC has been established **/
372     bool masterOccSet;
373 
374     /** @brief True when the master OCC is active **/
375     bool masterActive;
376 
377     /** @brief True when the ecoModes are supported for this system **/
378     bool ecoModeSupport = false;
379 
380     /** @brief List of customer supported power modes **/
381     std::set<SysPwrMode> customerModeList = {
382         SysPwrMode::STATIC, SysPwrMode::POWER_SAVING, SysPwrMode::MAX_PERF};
383 
384     /** @brief List of OEM supported power modes **/
385     std::set<SysPwrMode> oemModeList = {SysPwrMode::SFP, SysPwrMode::FFO,
386                                         SysPwrMode::MAX_FREQ};
387 
388     /** @brief IPS status data filename to read */
389     const fs::path ipsStatusFile =
390         std::filesystem::path{OCC_HWMON_PATH} /
391         std::filesystem::path{OCC_MASTER_NAME} / "occ_ips_status";
392 
393     /** @brief Current state of error watching */
394     bool watching = false;
395 
396     /** @brief Set at IPS object creation and cleared after sending IPS data */
397     bool needToSendIpsData = false;
398 
399     /** @brief Object path for IPS on DBUS */
400     const char* ipsObjectPath;
401 
402     /** @brief IPS DBUS Object */
403     std::unique_ptr<IpsInterface> ipsObject;
404 
405     /** @brief register for the callback from the POLL IPS changed event */
406     void registerIpsStatusCallBack();
407 
408     /** @brief Get the current power mode property
409      *
410      * @param[out] currentMode - current system power mode
411      * @param[out] oemModeData - frequency data for some OEM mode
412      *
413      * @return true if data read successfully
414      */
415     bool getMode(SysPwrMode& currentMode, uint16_t& oemModeData);
416 
417     /** @brief Update the power mode property on DBus
418      *
419      * @param[in]  newMode - desired power mode
420      *
421      * @return true on success
422      */
423     bool updateDbusMode(const SysPwrMode newMode);
424 
425     /** @brief Callback for IPS setting changes
426      *
427      * Process change and inform OCC
428      *
429      * @param[in]  msg - Data associated with IPS change signal
430      *
431      */
432     void ipsChanged(sdbusplus::message_t& msg);
433 
434     /** @brief Get the Idle Power Saver properties
435      *
436      *  @param[out] enabled - Idle Power Save status (true = enabled)
437      *  @param[out] enterUtil - IPS Enter Utilization (%)
438      *  @param[out] enterTime - IPS Enter Time (seconds)
439      *  @param[out] exitUtil - IPS Exit Utilization (%)
440      *  @param[out] exitTime - IPS Exit Time (seconds)
441      *
442      * @return true if data read successfully
443      */
444     bool getIPSParms(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
445                      uint8_t& exitUtil, uint16_t& exitTime);
446 
447     /** Update the Idle Power Saver data on DBus
448      *
449      *  @param[in] enabled - Idle Power Save status (true = enabled)
450      *  @param[in] enterUtil - IPS Enter Utilization (%)
451      *  @param[in] enterTime - IPS Enter Time (seconds)
452      *  @param[in] exitUtil - IPS Exit Utilization (%)
453      *  @param[in] exitTime - IPS Exit Time (seconds)
454      *
455      *  @return true if parameters were set successfully
456      */
457     bool updateDbusIPS(const bool enabled, const uint8_t enterUtil,
458                        const uint16_t enterTime, const uint8_t exitUtil,
459                        const uint16_t exitTime);
460 
461     /** @brief Callback for entity manager default changes
462      *
463      * Called when PowerModeProperties defaults are available
464      */
465     void defaultsReady(sdbusplus::message_t& msg);
466 
467     /** @brief Get the default power mode property for this system type
468      *
469      * @param[out] defaultMode - default system power mode
470      *
471      * @return true if data read successfully
472      */
473     bool getDefaultMode(SysPwrMode& defaultMode);
474 
475     /** @brief Get the default Idle Power Saver properties for this system type
476      *
477      *  @param[out] enabled - Idle Power Save status (true = enabled)
478      *  @param[out] enterUtil - IPS Enter Utilization (%)
479      *  @param[out] enterTime - IPS Enter Time (seconds)
480      *  @param[out] exitUtil - IPS Exit Utilization (%)
481      *  @param[out] exitTime - IPS Exit Time (seconds)
482      *
483      *  @return true if parameters were read successfully
484      */
485     bool getDefaultIPSParms(bool& enabled, uint8_t& enterUtil,
486                             uint16_t& enterTime, uint8_t& exitUtil,
487                             uint16_t& exitTime);
488 
489     /** @brief Read the default Idle Power Saver parameters and save them to the
490      * DBUS so they will get used
491      *
492      * @return true if restore was successful
493      */
494     bool useDefaultIPSParms();
495 
496     /** @brief Read the supported power modes from entity-manager and update
497      * AllowedPowerModes on dbus
498      *
499      * @return true if data was found/updated
500      */
501     bool getSupportedModes();
502 
503     /** @brief Create IPS DBUS Object */
504     void createIpsObject();
505 
506     /** @brief Remove IPS DBUS Object */
507     void removeIpsObject();
508 
509     /** @brief callback for the POLL IPS changed event
510      *
511      *  @param[in] es       - Populated event source
512      *  @param[in] fd       - Associated File descriptor
513      *  @param[in] revents  - Type of event
514      *  @param[in] userData - User data that was passed during registration
515      */
516     static int ipsStatusCallBack(sd_event_source* es, int fd, uint32_t revents,
517                                  void* userData);
518 
519     /** @brief Opens the IPS file and populates fd */
520     bool openIpsFile();
521 
522     /** @brief sd_event wrapped in unique_ptr */
523     EventPtr& event;
524 
525     /** @brief event source wrapped in unique_ptr */
526     EventSourcePtr eventSource;
527 
528     /** @brief When the ips status event is received, analyzes it */
529     virtual void analyzeIpsEvent();
530 
531   protected:
532     /** @brief File descriptor to watch for errors */
533     int fd = -1;
534 };
535 
536 } // namespace powermode
537 
538 } // namespace occ
539 
540 } // namespace open_power
541