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] managerRef - manager object reference 253 * @param[in] modePath - Power Mode dbus path 254 * @param[in] ipsPath - Idle Power Saver dbus path 255 */ 256 explicit PowerMode(const Manager& managerRef, const char* modePath, 257 const char* ipsPath, EventPtr& event); 258 259 /** @brief Initialize the persistent data with default values 260 * 261 * @return true if initialization completed 262 */ 263 bool initPersistentData(); 264 265 /** @brief Set the power mode lock (dbus method) 266 * 267 * @return true if successful 268 */ 269 bool powerModeLock(); 270 271 /** @brief Get the power mode lock status (dbus method) 272 * 273 * @return true if locked 274 */ 275 bool powerModeLockStatus(); 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 */ setMasterActive(const bool isActive=true)307 void setMasterActive(const bool isActive = true) 308 { 309 masterActive = isActive; 310 }; 311 312 /** @brief Starts to monitor for IPS active state change conditions 313 * 314 * @param[in] poll - Indicates whether or not the IPS state file should 315 * actually be read for changes. 316 */ 317 void addIpsWatch(bool poll = true); 318 319 /** @brief Removes IPS active watch */ 320 void removeIpsWatch(); 321 322 /** @brief Set dbus property to SAFE Mode(true) or clear SAFE Mode(false)*/ 323 void updateDbusSafeMode(const bool safeMode); 324 325 /** @brief override the set/get MODE function 326 * 327 * @param[in] value - Intended value 328 * 329 * @return - the value or Updated value of the property 330 */ 331 Base::Mode::PowerMode powerMode(Base::Mode::PowerMode value) override; 332 333 /** @brief Determine if the supplied mode is valid for the system 334 * 335 * @param[in] mode - potential mode 336 * 337 * @return - true if the mode is valid 338 */ 339 bool isValidMode(const SysPwrMode mode); 340 341 /** @brief If IPS is supported, set flag indicating need to send IPS data */ needToSendIPS()342 void needToSendIPS() 343 { 344 if (ipsObject) 345 { 346 needToSendIpsData = true; 347 } 348 } 349 350 private: 351 /** @brief OCC manager object */ 352 const Manager& manager; 353 354 /** @brief Pass-through occ path on the bus */ 355 std::string path; 356 357 /** @brief OCC instance number */ 358 int occInstance; 359 360 /** @brief Object to send commands to the OCC */ 361 std::unique_ptr<open_power::occ::OccCommand> occCmd; 362 363 /** @brief Used to subscribe to dbus IPS property changes **/ 364 sdbusplus::bus::match_t ipsMatch; 365 366 /** @brief Used to subscribe to dbus defaults property changes **/ 367 sdbusplus::bus::match_t defaultsUpdateMatch; 368 369 OccPersistData persistedData; 370 371 /** @brief True when the master OCC has been established **/ 372 bool masterOccSet; 373 374 /** @brief True when the master OCC is active **/ 375 bool masterActive; 376 377 /** @brief True when the ecoModes are supported for this system **/ 378 bool ecoModeSupport = false; 379 380 /** @brief List of customer supported power modes **/ 381 std::set<SysPwrMode> customerModeList = { 382 SysPwrMode::STATIC, SysPwrMode::POWER_SAVING, SysPwrMode::MAX_PERF}; 383 384 /** @brief List of OEM supported power modes **/ 385 std::set<SysPwrMode> oemModeList = {SysPwrMode::SFP, SysPwrMode::FFO, 386 SysPwrMode::MAX_FREQ}; 387 388 /** @brief IPS status data filename to read */ 389 const fs::path ipsStatusFile = 390 std::filesystem::path{OCC_HWMON_PATH} / 391 std::filesystem::path{OCC_MASTER_NAME} / "occ_ips_status"; 392 393 /** @brief Current state of error watching */ 394 bool watching = false; 395 396 /** @brief Set at IPS object creation and cleared after sending IPS data */ 397 bool needToSendIpsData = false; 398 399 /** @brief Object path for IPS on DBUS */ 400 const char* ipsObjectPath; 401 402 /** @brief IPS DBUS Object */ 403 std::unique_ptr<IpsInterface> ipsObject; 404 405 /** @brief register for the callback from the POLL IPS changed event */ 406 void registerIpsStatusCallBack(); 407 408 /** @brief Get the current power mode property 409 * 410 * @param[out] currentMode - current system power mode 411 * @param[out] oemModeData - frequency data for some OEM mode 412 * 413 * @return true if data read successfully 414 */ 415 bool getMode(SysPwrMode& currentMode, uint16_t& oemModeData); 416 417 /** @brief Update the power mode property on DBus 418 * 419 * @param[in] newMode - desired power mode 420 * 421 * @return true on success 422 */ 423 bool updateDbusMode(const SysPwrMode newMode); 424 425 /** @brief Callback for IPS setting changes 426 * 427 * Process change and inform OCC 428 * 429 * @param[in] msg - Data associated with IPS change signal 430 * 431 */ 432 void ipsChanged(sdbusplus::message_t& msg); 433 434 /** @brief Get the Idle Power Saver properties 435 * 436 * @param[out] enabled - Idle Power Save status (true = enabled) 437 * @param[out] enterUtil - IPS Enter Utilization (%) 438 * @param[out] enterTime - IPS Enter Time (seconds) 439 * @param[out] exitUtil - IPS Exit Utilization (%) 440 * @param[out] exitTime - IPS Exit Time (seconds) 441 * 442 * @return true if data read successfully 443 */ 444 bool getIPSParms(bool& enabled, uint8_t& enterUtil, uint16_t& enterTime, 445 uint8_t& exitUtil, uint16_t& exitTime); 446 447 /** Update the Idle Power Saver data on DBus 448 * 449 * @param[in] enabled - Idle Power Save status (true = enabled) 450 * @param[in] enterUtil - IPS Enter Utilization (%) 451 * @param[in] enterTime - IPS Enter Time (seconds) 452 * @param[in] exitUtil - IPS Exit Utilization (%) 453 * @param[in] exitTime - IPS Exit Time (seconds) 454 * 455 * @return true if parameters were set successfully 456 */ 457 bool updateDbusIPS(const bool enabled, const uint8_t enterUtil, 458 const uint16_t enterTime, const uint8_t exitUtil, 459 const uint16_t exitTime); 460 461 /** @brief Callback for entity manager default changes 462 * 463 * Called when PowerModeProperties defaults are available 464 */ 465 void defaultsReady(sdbusplus::message_t& msg); 466 467 /** @brief Get the default power mode property for this system type 468 * 469 * @param[out] defaultMode - default system power mode 470 * 471 * @return true if data read successfully 472 */ 473 bool getDefaultMode(SysPwrMode& defaultMode); 474 475 /** @brief Get the default Idle Power Saver properties for this system type 476 * 477 * @param[out] enabled - Idle Power Save status (true = enabled) 478 * @param[out] enterUtil - IPS Enter Utilization (%) 479 * @param[out] enterTime - IPS Enter Time (seconds) 480 * @param[out] exitUtil - IPS Exit Utilization (%) 481 * @param[out] exitTime - IPS Exit Time (seconds) 482 * 483 * @return true if parameters were read successfully 484 */ 485 bool getDefaultIPSParms(bool& enabled, uint8_t& enterUtil, 486 uint16_t& enterTime, uint8_t& exitUtil, 487 uint16_t& exitTime); 488 489 /** @brief Read the default Idle Power Saver parameters and save them to the 490 * DBUS so they will get used 491 * 492 * @return true if restore was successful 493 */ 494 bool useDefaultIPSParms(); 495 496 /** @brief Read the supported power modes from entity-manager and update 497 * AllowedPowerModes on dbus 498 * 499 * @return true if data was found/updated 500 */ 501 bool getSupportedModes(); 502 503 /** @brief Create IPS DBUS Object */ 504 void createIpsObject(); 505 506 /** @brief Remove IPS DBUS Object */ 507 void removeIpsObject(); 508 509 /** @brief callback for the POLL IPS changed event 510 * 511 * @param[in] es - Populated event source 512 * @param[in] fd - Associated File descriptor 513 * @param[in] revents - Type of event 514 * @param[in] userData - User data that was passed during registration 515 */ 516 static int ipsStatusCallBack(sd_event_source* es, int fd, uint32_t revents, 517 void* userData); 518 519 /** @brief Opens the IPS file and populates fd */ 520 bool openIpsFile(); 521 522 /** @brief sd_event wrapped in unique_ptr */ 523 EventPtr& event; 524 525 /** @brief event source wrapped in unique_ptr */ 526 EventSourcePtr eventSource; 527 528 /** @brief When the ips status event is received, analyzes it */ 529 virtual void analyzeIpsEvent(); 530 531 protected: 532 /** @brief File descriptor to watch for errors */ 533 int fd = -1; 534 }; 535 536 } // namespace powermode 537 538 } // namespace occ 539 540 } // namespace open_power 541