blob: dbd68eb594c78537403a993d170d5e31677372fc [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";
38
Chris Cain1d51da22021-09-21 14:13:41 -050039constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
40constexpr auto PIPS_INTERFACE =
41 "xyz.openbmc_project.Control.Power.IdlePowerSaver";
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050042constexpr auto IPS_ACTIVE_PROP = "Active";
Chris Cain1d51da22021-09-21 14:13:41 -050043constexpr auto IPS_ENABLED_PROP = "Enabled";
44constexpr auto IPS_ENTER_UTIL = "EnterUtilizationPercent";
45constexpr auto IPS_ENTER_TIME = "EnterDwellTime";
46constexpr auto IPS_EXIT_UTIL = "ExitUtilizationPercent";
47constexpr auto IPS_EXIT_TIME = "ExitDwellTime";
48
Chris Cain1be43372021-12-09 19:29:37 -060049const auto PMODE_DEFAULT_INTERFACE =
50 "xyz.openbmc_project.Configuration.PowerModeProperties"s;
51
Chris Cain36f9cde2021-11-22 11:18:21 -060052/** @brief Query the current Hypervisor target
53 * @return true if the current Hypervisor target is PowerVM
54 */
55bool isPowerVM();
56
Chris Cain78e86012021-03-04 16:15:31 -060057/** @brief Convert power mode string to OCC SysPwrMode value
58 *
59 * @param[in] i_modeString - power mode string
60 *
61 * @return SysPwrMode or SysPwrMode::NO_CHANGE if not found
62 */
63SysPwrMode convertStringToMode(const std::string& i_modeString);
64
Chris Cain1be43372021-12-09 19:29:37 -060065struct PowerModeData
Chris Cain36f9cde2021-11-22 11:18:21 -060066{
Chris Cain1be43372021-12-09 19:29:37 -060067 bool modeInitialized = false;
68 SysPwrMode mode = SysPwrMode::NO_CHANGE;
69 uint16_t oemModeData = 0x0000;
70 bool ipsInitialized = false;
71 bool ipsEnabled = true;
72 uint8_t ipsEnterUtil = 0;
73 uint16_t ipsEnterTime = 0;
74 uint8_t ipsExitUtil = 0;
75 uint16_t ipsExitTime = 0;
Chris Cain36f9cde2021-11-22 11:18:21 -060076
77 /** @brief Function specifying data to archive for cereal.
78 */
79 template <class Archive>
80 void serialize(Archive& archive)
81 {
Chris Cain1be43372021-12-09 19:29:37 -060082 archive(modeInitialized, mode, oemModeData, ipsInitialized, ipsEnabled,
83 ipsEnterUtil, ipsEnterTime, ipsExitUtil, ipsExitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -060084 }
85};
86
87/** @class OccPersistData
88 * @brief Provides persistent container to store data for OCC
89 *
90 * Data is stored via cereal
91 */
92class OccPersistData
93{
94 public:
95 ~OccPersistData() = default;
96 OccPersistData(const OccPersistData&) = default;
97 OccPersistData& operator=(const OccPersistData&) = default;
98 OccPersistData(OccPersistData&&) = default;
99 OccPersistData& operator=(OccPersistData&&) = default;
100
Chris Cain1be43372021-12-09 19:29:37 -0600101 /** @brief Loads any saved power mode data */
Chris Cain36f9cde2021-11-22 11:18:21 -0600102 OccPersistData()
103 {
104 load();
105 }
106
107 /** @brief Save Power Mode data to persistent file
108 *
Chris Cain1be43372021-12-09 19:29:37 -0600109 * @param[in] newMode - desired System Power Mode
110 * @param[in] oemModeData - data required by some OEM Power Modes
Chris Cain36f9cde2021-11-22 11:18:21 -0600111 */
Chris Cain1be43372021-12-09 19:29:37 -0600112 void updateMode(const SysPwrMode newMode, const uint16_t oemModeData)
Chris Cain36f9cde2021-11-22 11:18:21 -0600113 {
Chris Cain1be43372021-12-09 19:29:37 -0600114 modeData.mode = newMode;
115 modeData.oemModeData = oemModeData;
116 modeData.modeInitialized = true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600117 save();
118 }
119
Chris Cain1be43372021-12-09 19:29:37 -0600120 /** @brief Write Idle Power Saver parameters to persistent file
Chris Cain36f9cde2021-11-22 11:18:21 -0600121 *
Chris Cain1be43372021-12-09 19:29:37 -0600122 * @param[in] enabled - Idle Power Save status (true = enabled)
123 * @param[in] enterUtil - IPS Enter Utilization (%)
124 * @param[in] enterTime - IPS Enter Time (seconds)
125 * @param[in] exitUtil - IPS Exit Utilization (%)
126 * @param[in] exitTime - IPS Exit Time (seconds)
Chris Cain36f9cde2021-11-22 11:18:21 -0600127 */
Chris Cain1be43372021-12-09 19:29:37 -0600128 void updateIPS(const bool enabled, const uint8_t enterUtil,
129 const uint16_t enterTime, const uint8_t exitUtil,
130 const uint16_t exitTime)
Chris Cain36f9cde2021-11-22 11:18:21 -0600131 {
Chris Cain1be43372021-12-09 19:29:37 -0600132 modeData.ipsEnabled = enabled;
133 modeData.ipsEnterUtil = enterUtil;
134 modeData.ipsEnterTime = enterTime;
135 modeData.ipsExitUtil = exitUtil;
136 modeData.ipsExitTime = exitTime;
137 modeData.ipsInitialized = true;
138 save();
139 }
140
141 /** @brief Return the Power Mode and mode data
142 *
143 * @param[out] mode - current system power mode
144 * @param[out] oemModeData - frequency data for some OEM mode
145 *
146 * @returns true if mode was available
147 */
148 bool getMode(SysPwrMode& mode, uint16_t& oemModeData) const
149 {
150 if (!modeData.modeInitialized)
Chris Cain36f9cde2021-11-22 11:18:21 -0600151 {
152 return false;
153 }
154
Chris Cain1be43372021-12-09 19:29:37 -0600155 mode = modeData.mode;
156 oemModeData = modeData.oemModeData;
Chris Cain36f9cde2021-11-22 11:18:21 -0600157 return true;
158 }
159
Chris Cain1be43372021-12-09 19:29:37 -0600160 /** @brief Get the Idle Power Saver properties from DBus
161 *
162 * @param[out] enabled - Idle Power Save status (true = enabled)
163 * @param[out] enterUtil - IPS Enter Utilization (%)
164 * @param[out] enterTime - IPS Enter Time (seconds)
165 * @param[out] exitUtil - IPS Exit Utilization (%)
166 * @param[out] exitTime - IPS Exit Time (seconds)
167 *
168 * @return true if parameters were read successfully
169 */
170 bool getIPS(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
171 uint8_t& exitUtil, uint16_t& exitTime)
172 {
173 if (!modeData.ipsInitialized)
174 {
175 return false;
176 }
177
178 enabled = modeData.ipsEnabled;
179 enterUtil = modeData.ipsEnterUtil;
180 enterTime = modeData.ipsEnterTime;
181 exitUtil = modeData.ipsExitUtil;
182 exitTime = modeData.ipsExitTime;
183 return true;
184 }
185
186 /** @brief Return true if the power mode is available */
187 bool modeAvailable()
188 {
189 return (modeData.modeInitialized);
190 }
191
Chris Caincde7bea2022-01-28 15:54:24 -0600192 /** @brief Return true if the IPS data is available */
Chris Cain1be43372021-12-09 19:29:37 -0600193 bool ipsAvailable()
194 {
195 return (modeData.ipsInitialized);
196 }
197
Chris Cain36f9cde2021-11-22 11:18:21 -0600198 /** @brief Saves the Power Mode data in the filesystem using cereal. */
199 void save();
200
Chris Cain1be43372021-12-09 19:29:37 -0600201 /** @brief Trace the Power Mode and IPS parameters. */
202 void print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600203
204 private:
Chris Cain1be43372021-12-09 19:29:37 -0600205 /** @brief Power Mode data filename to store persistent data */
206 static constexpr auto powerModeFilename = "powerModeData";
Chris Cain36f9cde2021-11-22 11:18:21 -0600207
Chris Cain1be43372021-12-09 19:29:37 -0600208 /** @brief Power Mode data object to be persisted */
209 PowerModeData modeData;
Chris Cain36f9cde2021-11-22 11:18:21 -0600210
211 /** @brief Loads the OEM mode data in the filesystem using cereal. */
212 void load();
213};
214
Chris Cain78e86012021-03-04 16:15:31 -0600215/** @class PowerMode
216 * @brief Monitors for changes to the power mode and notifies occ
217 *
218 * The customer power mode is provided to the OCC by host TMGT when the occ
219 * first goes active or is reset. This code is responsible for sending
220 * the power mode to the OCC if the mode is changed while the occ is active.
221 */
222
Chris Cain1be43372021-12-09 19:29:37 -0600223class PowerMode : public ModeInterface, public IpsInterface
Chris Cain78e86012021-03-04 16:15:31 -0600224{
225 public:
226 /** @brief PowerMode object to inform occ of changes to mode
227 *
228 * This object will monitor for changes to the power mode setting.
229 * If a change is detected, and the occ is active, then this object will
230 * notify the OCC of the change.
231 *
Chris Cain1be43372021-12-09 19:29:37 -0600232 * @param[in] managerRef - manager object reference
233 * @param[in] modePath - Power Mode dbus path
234 * @param[in] ipsPath - Idle Power Saver dbus path
Chris Cain78e86012021-03-04 16:15:31 -0600235 */
Chris Cain1be43372021-12-09 19:29:37 -0600236 explicit PowerMode(const Manager& managerRef, const char* modePath,
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500237 const char* ipsPath
238#ifdef POWER10
239 ,
240 EventPtr& event
241#endif
242 ) :
Chris Cain1be43372021-12-09 19:29:37 -0600243 ModeInterface(utils::getBus(), modePath, false),
244 IpsInterface(utils::getBus(), ipsPath, false), manager(managerRef),
Chris Cain78e86012021-03-04 16:15:31 -0600245 pmodeMatch(utils::getBus(),
246 sdbusplus::bus::match::rules::propertiesChanged(
247 PMODE_PATH, PMODE_INTERFACE),
Chris Cain36f9cde2021-11-22 11:18:21 -0600248 [this](auto& msg) { this->modeChanged(msg); }),
249 ipsMatch(utils::getBus(),
250 sdbusplus::bus::match::rules::propertiesChanged(
251 PIPS_PATH, PIPS_INTERFACE),
252 [this](auto& msg) { this->ipsChanged(msg); }),
Chris Cain1be43372021-12-09 19:29:37 -0600253 defaultsUpdateMatch(
254 utils::getBus(),
255 sdbusplus::bus::match::rules::propertiesChangedNamespace(
256 "/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE),
257 [this](auto& msg) { this->defaultsReady(msg); }),
258 masterOccSet(false), masterActive(false)
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500259#ifdef POWER10
260 ,
261 event(event)
262#endif
Chris Cain1be43372021-12-09 19:29:37 -0600263 {
264 // restore Power Mode to DBus
265 SysPwrMode currentMode;
266 uint16_t oemModeData = 0;
267 if (getMode(currentMode, oemModeData))
268 {
269 updateDbusMode(currentMode);
270 }
271 // restore Idle Power Saver parameters to DBus
272 uint8_t enterUtil, exitUtil;
273 uint16_t enterTime, exitTime;
274 bool ipsEnabled;
275 if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime))
276 {
277 updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
278 }
279 };
Chris Cain36f9cde2021-11-22 11:18:21 -0600280
Chris Cain1be43372021-12-09 19:29:37 -0600281 /** @brief Initialize the persistent data with default values
282 *
283 * @return true if initialization completed
284 */
285 bool initPersistentData();
286
287 /** @brief Set the current power mode property
288 *
289 * @param[in] newMode - desired system power mode
290 * @param[in] oemModeData - data required by some OEM Power Modes
291 *
292 * @return true if mode accepted
293 */
294 bool setMode(const SysPwrMode newMode, const uint16_t oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600295
296 /** @brief Send mode change command to the master OCC
297 * @return SUCCESS on success
298 */
299 CmdStatus sendModeChange();
300
301 /** @brief Send Idle Power Saver config data to the master OCC
302 * @return SUCCESS on success
303 */
304 CmdStatus sendIpsData();
305
Chris Cain6fa848a2022-01-24 14:54:38 -0600306 /** @brief Set the master OCC path
307 *
308 * @param[in] occPath - hwmon path for master OCC
309 */
310 void setMasterOcc(const std::string& occPath);
311
Chris Cain36f9cde2021-11-22 11:18:21 -0600312 /** @brief Notify object of master OCC state. If not acitve, no
313 * commands will be sent to the master OCC
314 *
315 * @param[in] isActive - true when master OCC is active
316 */
317 void setMasterActive(const bool isActive = true)
318 {
319 masterActive = isActive;
320 };
Chris Cain78e86012021-03-04 16:15:31 -0600321
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500322#ifdef POWER10
323 /** @brief Starts to monitor for IPS active state change conditions
324 *
325 * @param[in] poll - Indicates whether or not the IPS state file should
326 * actually be read for changes.
327 */
328 void addIpsWatch(bool poll = true);
329
330 /** @brief Removes IPS active watch */
331 void removeIpsWatch();
332#endif
333
Chris Cain78e86012021-03-04 16:15:31 -0600334 private:
Chris Cain36f9cde2021-11-22 11:18:21 -0600335 /** @brief OCC manager object */
336 const Manager& manager;
337
338 /** @brief Pass-through occ path on the bus */
339 std::string path;
340
341 /** @brief OCC instance number */
342 int occInstance;
343
344 /** @brief Object to send commands to the OCC */
Chris Cain6fa848a2022-01-24 14:54:38 -0600345 std::unique_ptr<open_power::occ::OccCommand> occCmd;
Chris Cain36f9cde2021-11-22 11:18:21 -0600346
347 /** @brief Used to subscribe to dbus pmode property changes **/
348 sdbusplus::bus::match_t pmodeMatch;
349
350 /** @brief Used to subscribe to dbus IPS property changes **/
351 sdbusplus::bus::match_t ipsMatch;
352
Chris Cain1be43372021-12-09 19:29:37 -0600353 /** @brief Used to subscribe to dbus defaults property changes **/
354 sdbusplus::bus::match_t defaultsUpdateMatch;
355
Chris Cain36f9cde2021-11-22 11:18:21 -0600356 OccPersistData persistedData;
357
Chris Cain6fa848a2022-01-24 14:54:38 -0600358 /** @brief True when the master OCC has been established */
359 bool masterOccSet;
360
361 /** @brief True when the master OCC is active */
Chris Cain36f9cde2021-11-22 11:18:21 -0600362 bool masterActive;
363
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500364#ifdef POWER10
365 /** @brief IPS status data filename to read */
366 const fs::path ipsStatusFile = std::filesystem::path{OCC_HWMON_PATH} /
367 std::filesystem::path{OCC_MASTER_NAME} /
368 "occ_ips_status";
369
370 /** @brief Current state of error watching */
371 bool watching = false;
372
373 /** @brief register for the callback from the POLL IPS changed event */
374 void registerIpsStatusCallBack();
375#endif
376
Chris Cain78e86012021-03-04 16:15:31 -0600377 /** @brief Callback for pmode setting changes
378 *
379 * Process change and inform OCC
380 *
381 * @param[in] msg - Data associated with pmode change signal
382 *
383 */
384 void modeChanged(sdbusplus::message::message& msg);
385
Chris Cain1be43372021-12-09 19:29:37 -0600386 /** @brief Get the current power mode property
387 *
388 * @param[out] currentMode - current system power mode
389 * @param[out] oemModeData - frequency data for some OEM mode
390 *
391 * @return true if data read successfully
Chris Cain1d51da22021-09-21 14:13:41 -0500392 */
Chris Cain1be43372021-12-09 19:29:37 -0600393 bool getMode(SysPwrMode& currentMode, uint16_t& oemModeData);
Chris Cain1d51da22021-09-21 14:13:41 -0500394
Chris Cain36f9cde2021-11-22 11:18:21 -0600395 /** @brief Update the power mode property on DBus
396 *
397 * @param[in] newMode - desired power mode
398 *
399 * @return true on success
400 */
401 bool updateDbusMode(const SysPwrMode newMode);
402
Chris Cain1d51da22021-09-21 14:13:41 -0500403 /** @brief Callback for IPS setting changes
404 *
405 * Process change and inform OCC
406 *
Chris Cain36f9cde2021-11-22 11:18:21 -0600407 * @param[in] msg - Data associated with IPS change signal
Chris Cain1d51da22021-09-21 14:13:41 -0500408 *
409 */
410 void ipsChanged(sdbusplus::message::message& msg);
411
Chris Cain1be43372021-12-09 19:29:37 -0600412 /** @brief Get the Idle Power Saver properties
413 *
414 * @param[out] enabled - Idle Power Save status (true = enabled)
415 * @param[out] enterUtil - IPS Enter Utilization (%)
416 * @param[out] enterTime - IPS Enter Time (seconds)
417 * @param[out] exitUtil - IPS Exit Utilization (%)
418 * @param[out] exitTime - IPS Exit Time (seconds)
419 *
420 * @return true if data read successfully
Chris Cain36f9cde2021-11-22 11:18:21 -0600421 */
Chris Cain1be43372021-12-09 19:29:37 -0600422 bool getIPSParms(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime,
423 uint8_t& exitUtil, uint16_t& exitTime);
424
425 /** Update the Idle Power Saver data on DBus
426 *
427 * @param[in] enabled - Idle Power Save status (true = enabled)
428 * @param[in] enterUtil - IPS Enter Utilization (%)
429 * @param[in] enterTime - IPS Enter Time (seconds)
430 * @param[in] exitUtil - IPS Exit Utilization (%)
431 * @param[in] exitTime - IPS Exit Time (seconds)
432 *
433 * @return true if parameters were set successfully
434 */
435 bool updateDbusIPS(const bool enabled, const uint8_t enterUtil,
436 const uint16_t enterTime, const uint8_t exitUtil,
437 const uint16_t exitTime);
438
439 /** @brief Callback for entity manager default changes
440 *
441 * Called when PowerModeProperties defaults are available
442 */
443 void defaultsReady(sdbusplus::message::message& msg);
444
445 /** @brief Get the default power mode property for this system type
446 *
447 * @param[out] defaultMode - default system power mode
448 *
449 * @return true if data read successfully
450 */
451 bool getDefaultMode(SysPwrMode& defaultMode);
452
453 /** @brief Get the default Idle Power Saver properties for this system type
454 *
455 * @param[out] enabled - Idle Power Save status (true = enabled)
456 * @param[out] enterUtil - IPS Enter Utilization (%)
457 * @param[out] enterTime - IPS Enter Time (seconds)
458 * @param[out] exitUtil - IPS Exit Utilization (%)
459 * @param[out] exitTime - IPS Exit Time (seconds)
460 *
461 * @return true if parameters were read successfully
462 */
463 bool getDefaultIPSParms(bool& enabled, uint8_t& enterUtil,
464 uint16_t& enterTime, uint8_t& exitUtil,
465 uint16_t& exitTime);
Chris Caincde7bea2022-01-28 15:54:24 -0600466
467 /** @brief Read the default Idle Power Saver parameters and save them to the
468 * DBUS so they will get used
469 *
470 * @return true if restore was successful
471 */
472 bool useDefaultIPSParms();
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500473
474#ifdef POWER10
475 /** @brief callback for the POLL IPS changed event
476 *
477 * @param[in] es - Populated event source
478 * @param[in] fd - Associated File descriptor
479 * @param[in] revents - Type of event
480 * @param[in] userData - User data that was passed during registration
481 */
482 static int ipsStatusCallBack(sd_event_source* es, int fd, uint32_t revents,
483 void* userData);
484
485 /** @brief Opens the IPS file and populates fd */
486 bool openIpsFile();
487
488 /** @brief sd_event wrapped in unique_ptr */
489 EventPtr& event;
490
491 /** @brief event source wrapped in unique_ptr */
492 EventSourcePtr eventSource;
493
494 /** @brief When the ips status event is received, analyzes it */
495 virtual void analyzeIpsEvent();
496
497 protected:
498 /** @brief File descriptor to watch for errors */
499 int fd = -1;
500#endif
Chris Cain1d51da22021-09-21 14:13:41 -0500501};
502
Chris Cain78e86012021-03-04 16:15:31 -0600503} // namespace powermode
504
505} // namespace occ
506
507} // namespace open_power
508#endif