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