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