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