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