blob: f0aca51fed8ac90216f8af0fe48046ba4ed4fb2f [file] [log] [blame]
Chris Cain78e86012021-03-04 16:15:31 -06001#pragma once
2
Chris Cain78e86012021-03-04 16:15:31 -06003#include "config.h"
4
George Liubddcf852021-09-08 08:46:22 +08005#ifdef POWER10
Chris Cain36f9cde2021-11-22 11:18:21 -06006#include "occ_command.hpp"
Chris Cain78e86012021-03-04 16:15:31 -06007
Chris Cain36f9cde2021-11-22 11:18:21 -06008#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>
Chris Cain78e86012021-03-04 16:15:31 -060014#include <sdbusplus/bus.hpp>
15#include <sdbusplus/bus/match.hpp>
Chris Cain1be43372021-12-09 19:29:37 -060016#include <xyz/openbmc_project/Control/Power/IdlePowerSaver/server.hpp>
17#include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060018
George Liubcef3b42021-09-10 12:39:02 +080019#include <filesystem>
George Liub5ca1012021-09-10 12:53:11 +080020
Chris Cain78e86012021-03-04 16:15:31 -060021namespace open_power
22{
23namespace occ
24{
Chris Cain36f9cde2021-11-22 11:18:21 -060025
26class Manager;
27
Chris Cain78e86012021-03-04 16:15:31 -060028namespace powermode
29{
Chris Cain1be43372021-12-09 19:29:37 -060030namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server;
31using ModeInterface = sdbusplus::server::object::object<Base::Mode>;
32using IpsInterface = sdbusplus::server::object::object<Base::IdlePowerSaver>;
33using namespace std::literals::string_literals;
Chris Cain78e86012021-03-04 16:15:31 -060034
35constexpr auto PMODE_PATH = "/xyz/openbmc_project/control/host0/power_mode";
36constexpr auto PMODE_INTERFACE = "xyz.openbmc_project.Control.Power.Mode";
37constexpr auto POWER_MODE_PROP = "PowerMode";
Sheldon Bailey31a2f132022-05-20 11:31:52 -050038constexpr auto POWER_SAFE_MODE_PROP = "SafeMode";
Chris Cain78e86012021-03-04 16:15:31 -060039
Chris Cain1d51da22021-09-21 14:13:41 -050040constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
41constexpr auto PIPS_INTERFACE =
42 "xyz.openbmc_project.Control.Power.IdlePowerSaver";
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050043constexpr auto IPS_ACTIVE_PROP = "Active";
Chris Cain1d51da22021-09-21 14:13:41 -050044constexpr auto IPS_ENABLED_PROP = "Enabled";
45constexpr auto IPS_ENTER_UTIL = "EnterUtilizationPercent";
46constexpr auto IPS_ENTER_TIME = "EnterDwellTime";
47constexpr auto IPS_EXIT_UTIL = "ExitUtilizationPercent";
48constexpr auto IPS_EXIT_TIME = "ExitDwellTime";
49
Chris Cain1be43372021-12-09 19:29:37 -060050const auto PMODE_DEFAULT_INTERFACE =
51 "xyz.openbmc_project.Configuration.PowerModeProperties"s;
52
Chris Cain36f9cde2021-11-22 11:18:21 -060053/** @brief Query the current Hypervisor target
54 * @return true if the current Hypervisor target is PowerVM
55 */
56bool isPowerVM();
57
Chris Cain78e86012021-03-04 16:15:31 -060058/** @brief Convert power mode string to OCC SysPwrMode value
59 *
60 * @param[in] i_modeString - power mode string
61 *
62 * @return SysPwrMode or SysPwrMode::NO_CHANGE if not found
63 */
64SysPwrMode convertStringToMode(const std::string& i_modeString);
65
Chris Cain1be43372021-12-09 19:29:37 -060066struct PowerModeData
Chris Cain36f9cde2021-11-22 11:18:21 -060067{
Chris Cain1be43372021-12-09 19:29:37 -060068 bool modeInitialized = false;
69 SysPwrMode mode = SysPwrMode::NO_CHANGE;
70 uint16_t oemModeData = 0x0000;
71 bool ipsInitialized = false;
72 bool ipsEnabled = true;
73 uint8_t ipsEnterUtil = 0;
74 uint16_t ipsEnterTime = 0;
75 uint8_t ipsExitUtil = 0;
76 uint16_t ipsExitTime = 0;
Chris Cain36f9cde2021-11-22 11:18:21 -060077
78 /** @brief Function specifying data to archive for cereal.
79 */
80 template <class Archive>
81 void serialize(Archive& archive)
82 {
Chris Cain1be43372021-12-09 19:29:37 -060083 archive(modeInitialized, mode, oemModeData, ipsInitialized, ipsEnabled,
84 ipsEnterUtil, ipsEnterTime, ipsExitUtil, ipsExitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -060085 }
86};
87
88/** @class OccPersistData
89 * @brief Provides persistent container to store data for OCC
90 *
91 * Data is stored via cereal
92 */
93class 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
Chris Cain1be43372021-12-09 19:29:37 -0600102 /** @brief Loads any saved power mode data */
Chris Cain36f9cde2021-11-22 11:18:21 -0600103 OccPersistData()
104 {
105 load();
106 }
107
108 /** @brief Save Power Mode data to persistent file
109 *
Chris Cain1be43372021-12-09 19:29:37 -0600110 * @param[in] newMode - desired System Power Mode
111 * @param[in] oemModeData - data required by some OEM Power Modes
Chris Cain36f9cde2021-11-22 11:18:21 -0600112 */
Chris Cain1be43372021-12-09 19:29:37 -0600113 void updateMode(const SysPwrMode newMode, const uint16_t oemModeData)
Chris Cain36f9cde2021-11-22 11:18:21 -0600114 {
Chris Cain1be43372021-12-09 19:29:37 -0600115 modeData.mode = newMode;
116 modeData.oemModeData = oemModeData;
117 modeData.modeInitialized = true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600118 save();
119 }
120
Chris Cain1be43372021-12-09 19:29:37 -0600121 /** @brief Write Idle Power Saver parameters to persistent file
Chris Cain36f9cde2021-11-22 11:18:21 -0600122 *
Chris Cain1be43372021-12-09 19:29:37 -0600123 * @param[in] enabled - Idle Power Save status (true = enabled)
124 * @param[in] enterUtil - IPS Enter Utilization (%)
125 * @param[in] enterTime - IPS Enter Time (seconds)
126 * @param[in] exitUtil - IPS Exit Utilization (%)
127 * @param[in] exitTime - IPS Exit Time (seconds)
Chris Cain36f9cde2021-11-22 11:18:21 -0600128 */
Chris Cain1be43372021-12-09 19:29:37 -0600129 void updateIPS(const bool enabled, const uint8_t enterUtil,
130 const uint16_t enterTime, const uint8_t exitUtil,
131 const uint16_t exitTime)
Chris Cain36f9cde2021-11-22 11:18:21 -0600132 {
Chris Cain1be43372021-12-09 19:29:37 -0600133 modeData.ipsEnabled = enabled;
134 modeData.ipsEnterUtil = enterUtil;
135 modeData.ipsEnterTime = enterTime;
136 modeData.ipsExitUtil = exitUtil;
137 modeData.ipsExitTime = exitTime;
138 modeData.ipsInitialized = true;
139 save();
140 }
141
142 /** @brief Return the Power Mode and mode data
143 *
144 * @param[out] mode - current system power mode
145 * @param[out] oemModeData - frequency data for some OEM mode
146 *
147 * @returns true if mode was available
148 */
149 bool getMode(SysPwrMode& mode, uint16_t& oemModeData) const
150 {
151 if (!modeData.modeInitialized)
Chris Cain36f9cde2021-11-22 11:18:21 -0600152 {
153 return false;
154 }
155
Chris Cain1be43372021-12-09 19:29:37 -0600156 mode = modeData.mode;
157 oemModeData = modeData.oemModeData;
Chris Cain36f9cde2021-11-22 11:18:21 -0600158 return true;
159 }
160
Chris Cain1be43372021-12-09 19:29:37 -0600161 /** @brief Get the Idle Power Saver properties from DBus
162 *
163 * @param[out] enabled - Idle Power Save status (true = enabled)
164 * @param[out] enterUtil - IPS Enter Utilization (%)
165 * @param[out] enterTime - IPS Enter Time (seconds)
166 * @param[out] exitUtil - IPS Exit Utilization (%)
167 * @param[out] exitTime - IPS Exit Time (seconds)
168 *
169 * @return true if parameters were read successfully
170 */
171 bool getIPS(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
172 uint8_t& exitUtil, uint16_t& exitTime)
173 {
174 if (!modeData.ipsInitialized)
175 {
176 return false;
177 }
178
179 enabled = modeData.ipsEnabled;
180 enterUtil = modeData.ipsEnterUtil;
181 enterTime = modeData.ipsEnterTime;
182 exitUtil = modeData.ipsExitUtil;
183 exitTime = modeData.ipsExitTime;
184 return true;
185 }
186
187 /** @brief Return true if the power mode is available */
188 bool modeAvailable()
189 {
190 return (modeData.modeInitialized);
191 }
192
Chris Caincde7bea2022-01-28 15:54:24 -0600193 /** @brief Return true if the IPS data is available */
Chris Cain1be43372021-12-09 19:29:37 -0600194 bool ipsAvailable()
195 {
196 return (modeData.ipsInitialized);
197 }
198
Chris Cain36f9cde2021-11-22 11:18:21 -0600199 /** @brief Saves the Power Mode data in the filesystem using cereal. */
200 void save();
201
Chris Cain1be43372021-12-09 19:29:37 -0600202 /** @brief Trace the Power Mode and IPS parameters. */
203 void print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600204
205 private:
Chris Cain1be43372021-12-09 19:29:37 -0600206 /** @brief Power Mode data filename to store persistent data */
207 static constexpr auto powerModeFilename = "powerModeData";
Chris Cain36f9cde2021-11-22 11:18:21 -0600208
Chris Cain1be43372021-12-09 19:29:37 -0600209 /** @brief Power Mode data object to be persisted */
210 PowerModeData modeData;
Chris Cain36f9cde2021-11-22 11:18:21 -0600211
212 /** @brief Loads the OEM mode data in the filesystem using cereal. */
213 void load();
214};
215
Chris Cain78e86012021-03-04 16:15:31 -0600216/** @class PowerMode
217 * @brief Monitors for changes to the power mode and notifies occ
218 *
219 * The customer power mode is provided to the OCC by host TMGT when the occ
220 * first goes active or is reset. This code is responsible for sending
221 * the power mode to the OCC if the mode is changed while the occ is active.
222 */
223
Chris Cain1be43372021-12-09 19:29:37 -0600224class PowerMode : public ModeInterface, public IpsInterface
Chris Cain78e86012021-03-04 16:15:31 -0600225{
226 public:
227 /** @brief PowerMode object to inform occ of changes to mode
228 *
229 * This object will monitor for changes to the power mode setting.
230 * If a change is detected, and the occ is active, then this object will
231 * notify the OCC of the change.
232 *
Chris Cain1be43372021-12-09 19:29:37 -0600233 * @param[in] managerRef - manager object reference
234 * @param[in] modePath - Power Mode dbus path
235 * @param[in] ipsPath - Idle Power Saver dbus path
Chris Cain78e86012021-03-04 16:15:31 -0600236 */
Chris Cain1be43372021-12-09 19:29:37 -0600237 explicit PowerMode(const Manager& managerRef, const char* modePath,
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500238 const char* ipsPath
239#ifdef POWER10
240 ,
241 EventPtr& event
242#endif
243 ) :
Chris Cain1be43372021-12-09 19:29:37 -0600244 ModeInterface(utils::getBus(), modePath, false),
245 IpsInterface(utils::getBus(), ipsPath, false), manager(managerRef),
Chris Cain78e86012021-03-04 16:15:31 -0600246 pmodeMatch(utils::getBus(),
247 sdbusplus::bus::match::rules::propertiesChanged(
248 PMODE_PATH, PMODE_INTERFACE),
Chris Cain36f9cde2021-11-22 11:18:21 -0600249 [this](auto& msg) { this->modeChanged(msg); }),
250 ipsMatch(utils::getBus(),
251 sdbusplus::bus::match::rules::propertiesChanged(
252 PIPS_PATH, PIPS_INTERFACE),
253 [this](auto& msg) { this->ipsChanged(msg); }),
Chris Cain1be43372021-12-09 19:29:37 -0600254 defaultsUpdateMatch(
255 utils::getBus(),
256 sdbusplus::bus::match::rules::propertiesChangedNamespace(
257 "/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE),
258 [this](auto& msg) { this->defaultsReady(msg); }),
259 masterOccSet(false), masterActive(false)
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500260#ifdef POWER10
261 ,
262 event(event)
263#endif
Chris Cain1be43372021-12-09 19:29:37 -0600264 {
265 // restore Power Mode to DBus
266 SysPwrMode currentMode;
267 uint16_t oemModeData = 0;
268 if (getMode(currentMode, oemModeData))
269 {
270 updateDbusMode(currentMode);
271 }
272 // restore Idle Power Saver parameters to DBus
273 uint8_t enterUtil, exitUtil;
274 uint16_t enterTime, exitTime;
275 bool ipsEnabled;
276 if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime))
277 {
278 updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
279 }
280 };
Chris Cain36f9cde2021-11-22 11:18:21 -0600281
Chris Cain1be43372021-12-09 19:29:37 -0600282 /** @brief Initialize the persistent data with default values
283 *
284 * @return true if initialization completed
285 */
286 bool initPersistentData();
287
288 /** @brief Set the current power mode property
289 *
290 * @param[in] newMode - desired system power mode
291 * @param[in] oemModeData - data required by some OEM Power Modes
292 *
293 * @return true if mode accepted
294 */
295 bool setMode(const SysPwrMode newMode, const uint16_t oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600296
297 /** @brief Send mode change command to the master OCC
298 * @return SUCCESS on success
299 */
300 CmdStatus sendModeChange();
301
302 /** @brief Send Idle Power Saver config data to the master OCC
303 * @return SUCCESS on success
304 */
305 CmdStatus sendIpsData();
306
Chris Cain6fa848a2022-01-24 14:54:38 -0600307 /** @brief Set the master OCC path
308 *
309 * @param[in] occPath - hwmon path for master OCC
310 */
311 void setMasterOcc(const std::string& occPath);
312
Chris Cain36f9cde2021-11-22 11:18:21 -0600313 /** @brief Notify object of master OCC state. If not acitve, no
314 * commands will be sent to the master OCC
315 *
316 * @param[in] isActive - true when master OCC is active
317 */
318 void setMasterActive(const bool isActive = true)
319 {
320 masterActive = isActive;
321 };
Chris Cain78e86012021-03-04 16:15:31 -0600322
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500323#ifdef POWER10
324 /** @brief Starts to monitor for IPS active state change conditions
325 *
326 * @param[in] poll - Indicates whether or not the IPS state file should
327 * actually be read for changes.
328 */
329 void addIpsWatch(bool poll = true);
330
331 /** @brief Removes IPS active watch */
332 void removeIpsWatch();
333#endif
334
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500335 /** @brief Set dbus property to SAFE Mode(true) or clear SAFE Mode(false)*/
336 void updateDbusSafeMode(const bool safeMode);
337
Chris Cain78e86012021-03-04 16:15:31 -0600338 private:
Chris Cain36f9cde2021-11-22 11:18:21 -0600339 /** @brief OCC manager object */
340 const Manager& manager;
341
342 /** @brief Pass-through occ path on the bus */
343 std::string path;
344
345 /** @brief OCC instance number */
346 int occInstance;
347
348 /** @brief Object to send commands to the OCC */
Chris Cain6fa848a2022-01-24 14:54:38 -0600349 std::unique_ptr<open_power::occ::OccCommand> occCmd;
Chris Cain36f9cde2021-11-22 11:18:21 -0600350
351 /** @brief Used to subscribe to dbus pmode property changes **/
352 sdbusplus::bus::match_t pmodeMatch;
353
354 /** @brief Used to subscribe to dbus IPS property changes **/
355 sdbusplus::bus::match_t ipsMatch;
356
Chris Cain1be43372021-12-09 19:29:37 -0600357 /** @brief Used to subscribe to dbus defaults property changes **/
358 sdbusplus::bus::match_t defaultsUpdateMatch;
359
Chris Cain36f9cde2021-11-22 11:18:21 -0600360 OccPersistData persistedData;
361
Chris Cain6fa848a2022-01-24 14:54:38 -0600362 /** @brief True when the master OCC has been established */
363 bool masterOccSet;
364
365 /** @brief True when the master OCC is active */
Chris Cain36f9cde2021-11-22 11:18:21 -0600366 bool masterActive;
367
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500368#ifdef POWER10
369 /** @brief IPS status data filename to read */
370 const fs::path ipsStatusFile = std::filesystem::path{OCC_HWMON_PATH} /
371 std::filesystem::path{OCC_MASTER_NAME} /
372 "occ_ips_status";
373
374 /** @brief Current state of error watching */
375 bool watching = false;
376
377 /** @brief register for the callback from the POLL IPS changed event */
378 void registerIpsStatusCallBack();
379#endif
380
Chris Cain78e86012021-03-04 16:15:31 -0600381 /** @brief Callback for pmode setting changes
382 *
383 * Process change and inform OCC
384 *
385 * @param[in] msg - Data associated with pmode change signal
386 *
387 */
388 void modeChanged(sdbusplus::message::message& msg);
389
Chris Cain1be43372021-12-09 19:29:37 -0600390 /** @brief Get the current power mode property
391 *
392 * @param[out] currentMode - current system power mode
393 * @param[out] oemModeData - frequency data for some OEM mode
394 *
395 * @return true if data read successfully
Chris Cain1d51da22021-09-21 14:13:41 -0500396 */
Chris Cain1be43372021-12-09 19:29:37 -0600397 bool getMode(SysPwrMode& currentMode, uint16_t& oemModeData);
Chris Cain1d51da22021-09-21 14:13:41 -0500398
Chris Cain36f9cde2021-11-22 11:18:21 -0600399 /** @brief Update the power mode property on DBus
400 *
401 * @param[in] newMode - desired power mode
402 *
403 * @return true on success
404 */
405 bool updateDbusMode(const SysPwrMode newMode);
406
Chris Cain1d51da22021-09-21 14:13:41 -0500407 /** @brief Callback for IPS setting changes
408 *
409 * Process change and inform OCC
410 *
Chris Cain36f9cde2021-11-22 11:18:21 -0600411 * @param[in] msg - Data associated with IPS change signal
Chris Cain1d51da22021-09-21 14:13:41 -0500412 *
413 */
414 void ipsChanged(sdbusplus::message::message& msg);
415
Chris Cain1be43372021-12-09 19:29:37 -0600416 /** @brief Get the Idle Power Saver properties
417 *
418 * @param[out] enabled - Idle Power Save status (true = enabled)
419 * @param[out] enterUtil - IPS Enter Utilization (%)
420 * @param[out] enterTime - IPS Enter Time (seconds)
421 * @param[out] exitUtil - IPS Exit Utilization (%)
422 * @param[out] exitTime - IPS Exit Time (seconds)
423 *
424 * @return true if data read successfully
Chris Cain36f9cde2021-11-22 11:18:21 -0600425 */
Chris Cain1be43372021-12-09 19:29:37 -0600426 bool getIPSParms(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
427 uint8_t& exitUtil, uint16_t& exitTime);
428
429 /** Update the Idle Power Saver data on DBus
430 *
431 * @param[in] enabled - Idle Power Save status (true = enabled)
432 * @param[in] enterUtil - IPS Enter Utilization (%)
433 * @param[in] enterTime - IPS Enter Time (seconds)
434 * @param[in] exitUtil - IPS Exit Utilization (%)
435 * @param[in] exitTime - IPS Exit Time (seconds)
436 *
437 * @return true if parameters were set successfully
438 */
439 bool updateDbusIPS(const bool enabled, const uint8_t enterUtil,
440 const uint16_t enterTime, const uint8_t exitUtil,
441 const uint16_t exitTime);
442
443 /** @brief Callback for entity manager default changes
444 *
445 * Called when PowerModeProperties defaults are available
446 */
447 void defaultsReady(sdbusplus::message::message& msg);
448
449 /** @brief Get the default power mode property for this system type
450 *
451 * @param[out] defaultMode - default system power mode
452 *
453 * @return true if data read successfully
454 */
455 bool getDefaultMode(SysPwrMode& defaultMode);
456
457 /** @brief Get the default Idle Power Saver properties for this system type
458 *
459 * @param[out] enabled - Idle Power Save status (true = enabled)
460 * @param[out] enterUtil - IPS Enter Utilization (%)
461 * @param[out] enterTime - IPS Enter Time (seconds)
462 * @param[out] exitUtil - IPS Exit Utilization (%)
463 * @param[out] exitTime - IPS Exit Time (seconds)
464 *
465 * @return true if parameters were read successfully
466 */
467 bool getDefaultIPSParms(bool& enabled, uint8_t& enterUtil,
468 uint16_t& enterTime, uint8_t& exitUtil,
469 uint16_t& exitTime);
Chris Caincde7bea2022-01-28 15:54:24 -0600470
471 /** @brief Read the default Idle Power Saver parameters and save them to the
472 * DBUS so they will get used
473 *
474 * @return true if restore was successful
475 */
476 bool useDefaultIPSParms();
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500477
478#ifdef POWER10
479 /** @brief callback for the POLL IPS changed event
480 *
481 * @param[in] es - Populated event source
482 * @param[in] fd - Associated File descriptor
483 * @param[in] revents - Type of event
484 * @param[in] userData - User data that was passed during registration
485 */
486 static int ipsStatusCallBack(sd_event_source* es, int fd, uint32_t revents,
487 void* userData);
488
489 /** @brief Opens the IPS file and populates fd */
490 bool openIpsFile();
491
492 /** @brief sd_event wrapped in unique_ptr */
493 EventPtr& event;
494
495 /** @brief event source wrapped in unique_ptr */
496 EventSourcePtr eventSource;
497
498 /** @brief When the ips status event is received, analyzes it */
499 virtual void analyzeIpsEvent();
500
501 protected:
502 /** @brief File descriptor to watch for errors */
503 int fd = -1;
504#endif
Chris Cain1d51da22021-09-21 14:13:41 -0500505};
506
Chris Cain78e86012021-03-04 16:15:31 -0600507} // namespace powermode
508
509} // namespace occ
510
511} // namespace open_power
512#endif