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