1 #include "powermode.hpp" 2 3 #include <fmt/core.h> 4 5 #include <com/ibm/Host/Target/server.hpp> 6 #include <phosphor-logging/log.hpp> 7 #include <xyz/openbmc_project/Control/Power/Mode/server.hpp> 8 9 #include <cassert> 10 #include <fstream> 11 #include <regex> 12 13 namespace open_power 14 { 15 namespace occ 16 { 17 namespace powermode 18 { 19 20 using namespace phosphor::logging; 21 using namespace std::literals::string_literals; 22 23 using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode; 24 25 // Set the Master OCC 26 void PowerMode::setMasterOcc(const std::string& masterOccPath) 27 { 28 if (masterOccSet) 29 { 30 if (masterOccPath != path) 31 { 32 log<level::ERR>( 33 fmt::format( 34 "PowerMode::setMasterOcc: Master changed (was OCC{}, {})", 35 occInstance, masterOccPath) 36 .c_str()); 37 if (occCmd) 38 { 39 occCmd.reset(); 40 } 41 } 42 } 43 path = masterOccPath; 44 occInstance = path.back() - '0'; 45 log<level::DEBUG>(fmt::format("PowerMode::setMasterOcc(OCC{}, {})", 46 occInstance, path.c_str()) 47 .c_str()); 48 if (!occCmd) 49 { 50 occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance, 51 path.c_str()); 52 } 53 masterOccSet = true; 54 }; 55 56 // Called when DBus power mode gets changed 57 void PowerMode::modeChanged(sdbusplus::message::message& msg) 58 { 59 std::map<std::string, std::variant<std::string>> properties{}; 60 std::string interface; 61 std::string propVal; 62 msg.read(interface, properties); 63 const auto modeEntry = properties.find(POWER_MODE_PROP); 64 if (modeEntry != properties.end()) 65 { 66 auto modeEntryValue = modeEntry->second; 67 propVal = std::get<std::string>(modeEntryValue); 68 SysPwrMode newMode = convertStringToMode(propVal); 69 if (newMode != SysPwrMode::NO_CHANGE) 70 { 71 // Update persisted data with new mode 72 persistedData.updateMode(newMode, 0); 73 74 log<level::INFO>( 75 fmt::format("DBus Power Mode Changed: {}", propVal).c_str()); 76 77 // Send mode change to OCC 78 sendModeChange(); 79 } 80 } 81 } 82 83 // Called from OCC PassThrough interface (via CE login / BMC command line) 84 bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t oemModeData) 85 { 86 if (updateDbusMode(newMode) == false) 87 { 88 // Unsupported mode 89 return false; 90 } 91 92 // Save mode 93 persistedData.updateMode(newMode, oemModeData); 94 95 // Send mode change to OCC 96 if (sendModeChange() != CmdStatus::SUCCESS) 97 { 98 // Mode change failed 99 return false; 100 } 101 102 return true; 103 } 104 105 // Convert PowerMode string to OCC SysPwrMode 106 // Returns NO_CHANGE if OEM or unsupported mode 107 SysPwrMode convertStringToMode(const std::string& i_modeString) 108 { 109 SysPwrMode pmode = SysPwrMode::NO_CHANGE; 110 111 Mode::PowerMode mode = Mode::convertPowerModeFromString(i_modeString); 112 if (mode == Mode::PowerMode::MaximumPerformance) 113 { 114 pmode = SysPwrMode::MAX_PERF; 115 } 116 else if (mode == Mode::PowerMode::PowerSaving) 117 { 118 pmode = SysPwrMode::POWER_SAVING; 119 } 120 else if (mode == Mode::PowerMode::Static) 121 { 122 pmode = SysPwrMode::STATIC; 123 } 124 else 125 { 126 if (mode != Mode::PowerMode::OEM) 127 { 128 log<level::ERR>( 129 fmt::format( 130 "convertStringToMode: Invalid Power Mode specified: {}", 131 i_modeString) 132 .c_str()); 133 } 134 } 135 136 return pmode; 137 } 138 139 // Check if Hypervisor target is PowerVM 140 bool isPowerVM() 141 { 142 namespace Hyper = sdbusplus::com::ibm::Host::server; 143 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor"; 144 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target"; 145 constexpr auto HYPE_PROP = "Target"; 146 147 bool powerVmTarget = false; 148 149 // This will throw exception on failure 150 auto& bus = utils::getBus(); 151 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE); 152 auto method = bus.new_method_call(service.c_str(), HYPE_PATH, 153 "org.freedesktop.DBus.Properties", "Get"); 154 method.append(HYPE_INTERFACE, HYPE_PROP); 155 auto reply = bus.call(method); 156 157 std::variant<std::string> hyperEntryValue; 158 reply.read(hyperEntryValue); 159 auto propVal = std::get<std::string>(hyperEntryValue); 160 if (Hyper::Target::convertHypervisorFromString(propVal) == 161 Hyper::Target::Hypervisor::PowerVM) 162 { 163 powerVmTarget = true; 164 } 165 166 log<level::DEBUG>( 167 fmt::format("isPowerVM returning {}", powerVmTarget).c_str()); 168 169 return powerVmTarget; 170 } 171 172 // Initialize persistent data and return true if successful 173 bool PowerMode::initPersistentData() 174 { 175 if (!persistedData.modeAvailable()) 176 { 177 // Read the default mode 178 SysPwrMode currentMode; 179 if (!getDefaultMode(currentMode)) 180 { 181 // Unable to read defaults 182 return false; 183 } 184 log<level::INFO>( 185 fmt::format("PowerMode::initPersistentData: Using default mode: {}", 186 currentMode) 187 .c_str()); 188 189 // Save default mode as current mode 190 persistedData.updateMode(currentMode, 0); 191 192 // Write default mode to DBus 193 updateDbusMode(currentMode); 194 } 195 196 if (!persistedData.ipsAvailable()) 197 { 198 // Read the default IPS parameters, write persistent file and update 199 // DBus 200 return useDefaultIPSParms(); 201 } 202 return true; 203 } 204 205 // Get the requested power mode and return true if successful 206 bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData) 207 { 208 currentMode = SysPwrMode::NO_CHANGE; 209 oemModeData = 0; 210 211 if (!persistedData.getMode(currentMode, oemModeData)) 212 { 213 // Persistent data not initialized, read defaults and update DBus 214 if (!initPersistentData()) 215 { 216 // Unable to read defaults from entity manager yet 217 return false; 218 } 219 return persistedData.getMode(currentMode, oemModeData); 220 } 221 222 return true; 223 } 224 225 // Set the power mode on DBus 226 bool PowerMode::updateDbusMode(const SysPwrMode newMode) 227 { 228 if (!VALID_POWER_MODE_SETTING(newMode) && 229 !VALID_OEM_POWER_MODE_SETTING(newMode)) 230 { 231 log<level::ERR>( 232 fmt::format( 233 "PowerMode::updateDbusMode - Requested power mode not supported: {}", 234 newMode) 235 .c_str()); 236 return false; 237 } 238 239 // Convert mode for DBus 240 ModeInterface::PowerMode dBusMode; 241 switch (newMode) 242 { 243 case SysPwrMode::STATIC: 244 dBusMode = Mode::PowerMode::Static; 245 break; 246 case SysPwrMode::POWER_SAVING: 247 dBusMode = Mode::PowerMode::PowerSaving; 248 break; 249 case SysPwrMode::MAX_PERF: 250 dBusMode = Mode::PowerMode::MaximumPerformance; 251 break; 252 default: 253 dBusMode = Mode::PowerMode::OEM; 254 } 255 256 // true = skip update signal 257 ModeInterface::setPropertyByName(POWER_MODE_PROP, dBusMode, true); 258 259 return true; 260 } 261 262 // Send mode change request to the master OCC 263 CmdStatus PowerMode::sendModeChange() 264 { 265 CmdStatus status; 266 267 if (!masterActive || !masterOccSet) 268 { 269 // Nothing to do 270 log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active"); 271 return CmdStatus::SUCCESS; 272 } 273 274 if (!isPowerVM()) 275 { 276 // Mode change is only supported on PowerVM systems 277 log<level::DEBUG>( 278 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems"); 279 return CmdStatus::SUCCESS; 280 } 281 282 SysPwrMode newMode; 283 uint16_t oemModeData = 0; 284 getMode(newMode, oemModeData); 285 286 if (VALID_POWER_MODE_SETTING(newMode) || 287 VALID_OEM_POWER_MODE_SETTING(newMode)) 288 { 289 std::vector<std::uint8_t> cmd, rsp; 290 cmd.reserve(9); 291 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE)); 292 cmd.push_back(0x00); // Data Length (2 bytes) 293 cmd.push_back(0x06); 294 cmd.push_back(0x30); // Data (Version) 295 cmd.push_back(uint8_t(OccState::NO_CHANGE)); 296 cmd.push_back(uint8_t(newMode)); 297 cmd.push_back(oemModeData >> 8); // Mode Data (Freq Point) 298 cmd.push_back(oemModeData & 0xFF); // 299 cmd.push_back(0x00); // reserved 300 log<level::INFO>( 301 fmt::format( 302 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)", 303 newMode, oemModeData, occInstance, cmd.size()) 304 .c_str()); 305 status = occCmd->send(cmd, rsp); 306 if (status == CmdStatus::SUCCESS) 307 { 308 if (rsp.size() == 5) 309 { 310 if (RspStatus::SUCCESS != RspStatus(rsp[2])) 311 { 312 log<level::ERR>( 313 fmt::format( 314 "PowerMode::sendModeChange: SET MODE failed with status 0x{:02X}", 315 rsp[2]) 316 .c_str()); 317 dump_hex(rsp); 318 status = CmdStatus::FAILURE; 319 } 320 } 321 else 322 { 323 log<level::ERR>( 324 "PowerMode::sendModeChange: INVALID SET MODE response"); 325 dump_hex(rsp); 326 status = CmdStatus::FAILURE; 327 } 328 } 329 else 330 { 331 if (status == CmdStatus::OPEN_FAILURE) 332 { 333 // OCC not active yet 334 status = CmdStatus::SUCCESS; 335 } 336 else 337 { 338 log<level::ERR>("PowerMode::sendModeChange: SET_MODE FAILED!"); 339 } 340 } 341 } 342 else 343 { 344 log<level::ERR>( 345 fmt::format( 346 "PowerMode::sendModeChange: Unable to set power mode to {}", 347 newMode) 348 .c_str()); 349 status = CmdStatus::FAILURE; 350 } 351 352 return status; 353 } 354 355 void PowerMode::ipsChanged(sdbusplus::message::message& msg) 356 { 357 bool parmsChanged = false; 358 std::string interface; 359 std::map<std::string, std::variant<bool, uint8_t, uint64_t>> 360 ipsProperties{}; 361 msg.read(interface, ipsProperties); 362 363 // Read persisted values 364 bool ipsEnabled; 365 uint8_t enterUtil, exitUtil; 366 uint16_t enterTime, exitTime; 367 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 368 369 // Check for any changed data 370 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP); 371 if (ipsEntry != ipsProperties.end()) 372 { 373 ipsEnabled = std::get<bool>(ipsEntry->second); 374 log<level::INFO>( 375 fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled) 376 .c_str()); 377 parmsChanged = true; 378 } 379 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL); 380 if (ipsEntry != ipsProperties.end()) 381 { 382 enterUtil = std::get<uint8_t>(ipsEntry->second); 383 log<level::INFO>( 384 fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil) 385 .c_str()); 386 parmsChanged = true; 387 } 388 ipsEntry = ipsProperties.find(IPS_ENTER_TIME); 389 if (ipsEntry != ipsProperties.end()) 390 { 391 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second)); 392 enterTime = 393 std::chrono::duration_cast<std::chrono::seconds>(ms).count(); 394 log<level::INFO>( 395 fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime) 396 .c_str()); 397 parmsChanged = true; 398 } 399 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL); 400 if (ipsEntry != ipsProperties.end()) 401 { 402 exitUtil = std::get<uint8_t>(ipsEntry->second); 403 log<level::INFO>( 404 fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil) 405 .c_str()); 406 parmsChanged = true; 407 } 408 ipsEntry = ipsProperties.find(IPS_EXIT_TIME); 409 if (ipsEntry != ipsProperties.end()) 410 { 411 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second)); 412 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count(); 413 log<level::INFO>( 414 fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime) 415 .c_str()); 416 parmsChanged = true; 417 } 418 419 if (parmsChanged) 420 { 421 if (exitUtil == 0) 422 { 423 // Setting the exitUtil to 0 will force restoring the default IPS 424 // parmeters (0 is not valid exit utilization) 425 log<level::INFO>( 426 "Idle Power Saver Exit Utilization is 0%. Restoring default parameters"); 427 // Read the default IPS parameters, write persistent file and update 428 // DBus 429 useDefaultIPSParms(); 430 } 431 else 432 { 433 // Update persistant data with new DBus values 434 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 435 exitTime); 436 } 437 438 // Trigger IPS data to get sent to the OCC 439 sendIpsData(); 440 } 441 442 return; 443 } 444 445 /** @brief Get the Idle Power Saver properties from persisted data 446 * @return true if IPS parameters were read 447 */ 448 bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil, 449 uint16_t& enterTime, uint8_t& exitUtil, 450 uint16_t& exitTime) 451 { 452 // Defaults: 453 ipsEnabled = true; // Enabled 454 enterUtil = 8; // Enter Utilization (8%) 455 enterTime = 240; // Enter Delay Time (240s) 456 exitUtil = 12; // Exit Utilization (12%) 457 exitTime = 10; // Exit Delay Time (10s) 458 459 if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 460 exitTime)) 461 { 462 // Persistent data not initialized, read defaults and update DBus 463 if (!initPersistentData()) 464 { 465 // Unable to read defaults from entity manager yet 466 return false; 467 } 468 469 persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 470 exitTime); 471 } 472 473 if (enterUtil > exitUtil) 474 { 475 log<level::ERR>( 476 fmt::format( 477 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both", 478 enterUtil, exitUtil) 479 .c_str()); 480 enterUtil = exitUtil; 481 } 482 483 return true; 484 } 485 486 // Set the Idle Power Saver data on DBus 487 bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil, 488 const uint16_t enterTime, const uint8_t exitUtil, 489 const uint16_t exitTime) 490 { 491 // true = skip update signal 492 IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true); 493 IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true); 494 // Convert time from seconds to ms 495 uint64_t msTime = enterTime * 1000; 496 IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true); 497 IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true); 498 msTime = exitTime * 1000; 499 IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true); 500 501 return true; 502 } 503 504 // Send Idle Power Saver config data to the master OCC 505 CmdStatus PowerMode::sendIpsData() 506 { 507 if (!masterActive || !masterOccSet) 508 { 509 // Nothing to do 510 return CmdStatus::SUCCESS; 511 } 512 513 if (!isPowerVM()) 514 { 515 // Idle Power Saver data is only supported on PowerVM systems 516 log<level::DEBUG>( 517 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems"); 518 return CmdStatus::SUCCESS; 519 } 520 521 bool ipsEnabled; 522 uint8_t enterUtil, exitUtil; 523 uint16_t enterTime, exitTime; 524 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 525 526 log<level::INFO>( 527 fmt::format( 528 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s", 529 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime) 530 .c_str()); 531 532 std::vector<std::uint8_t> cmd, rsp; 533 cmd.reserve(12); 534 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA)); 535 cmd.push_back(0x00); // Data Length (2 bytes) 536 cmd.push_back(0x09); // 537 cmd.push_back(0x11); // Config Format: IPS Settings 538 cmd.push_back(0x00); // Version 539 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable 540 cmd.push_back(enterTime >> 8); // Enter Delay Time 541 cmd.push_back(enterTime & 0xFF); // 542 cmd.push_back(enterUtil); // Enter Utilization 543 cmd.push_back(exitTime >> 8); // Exit Delay Time 544 cmd.push_back(exitTime & 0xFF); // 545 cmd.push_back(exitUtil); // Exit Utilization 546 log<level::INFO>(fmt::format("PowerMode::sendIpsData: SET_CFG_DATA[IPS] " 547 "command to OCC{} ({} bytes)", 548 occInstance, cmd.size()) 549 .c_str()); 550 CmdStatus status = occCmd->send(cmd, rsp); 551 if (status == CmdStatus::SUCCESS) 552 { 553 if (rsp.size() == 5) 554 { 555 if (RspStatus::SUCCESS != RspStatus(rsp[2])) 556 { 557 log<level::ERR>( 558 fmt::format( 559 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}", 560 rsp[2]) 561 .c_str()); 562 dump_hex(rsp); 563 status = CmdStatus::FAILURE; 564 } 565 } 566 else 567 { 568 log<level::ERR>( 569 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response"); 570 dump_hex(rsp); 571 status = CmdStatus::FAILURE; 572 } 573 } 574 else 575 { 576 if (status == CmdStatus::OPEN_FAILURE) 577 { 578 // OCC not active yet 579 status = CmdStatus::SUCCESS; 580 } 581 else 582 { 583 log<level::ERR>( 584 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] FAILED!"); 585 } 586 } 587 588 return status; 589 } 590 591 // Print the current values 592 void OccPersistData::print() 593 { 594 if (modeData.modeInitialized) 595 { 596 log<level::INFO>( 597 fmt::format( 598 "OccPersistData: Mode: 0x{:02X}, OEM Mode Data: {} (0x{:04X})", 599 modeData.mode, modeData.oemModeData, modeData.oemModeData) 600 .c_str()); 601 } 602 if (modeData.ipsInitialized) 603 { 604 log<level::INFO>( 605 fmt::format( 606 "OccPersistData: IPS enabled:{}, enter:{}%/{}s, exit:{}%/{}s", 607 modeData.ipsEnabled, modeData.ipsEnterUtil, 608 modeData.ipsEnterTime, modeData.ipsExitUtil, 609 modeData.ipsExitTime) 610 .c_str()); 611 } 612 } 613 614 // Saves the OEM mode data in the filesystem using cereal. 615 void OccPersistData::save() 616 { 617 std::filesystem::path opath = 618 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename; 619 620 if (!std::filesystem::exists(opath.parent_path())) 621 { 622 std::filesystem::create_directory(opath.parent_path()); 623 } 624 625 log<level::DEBUG>( 626 fmt::format( 627 "OccPersistData::save: Writing Power Mode persisted data to {}", 628 opath.c_str()) 629 .c_str()); 630 // print(); 631 632 std::ofstream stream{opath.c_str()}; 633 cereal::JSONOutputArchive oarchive{stream}; 634 635 oarchive(modeData); 636 } 637 638 // Loads the OEM mode data in the filesystem using cereal. 639 void OccPersistData::load() 640 { 641 642 std::filesystem::path ipath = 643 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename; 644 645 if (!std::filesystem::exists(ipath)) 646 { 647 modeData.modeInitialized = false; 648 modeData.ipsInitialized = false; 649 return; 650 } 651 652 log<level::DEBUG>( 653 fmt::format( 654 "OccPersistData::load: Reading Power Mode persisted data from {}", 655 ipath.c_str()) 656 .c_str()); 657 try 658 { 659 std::ifstream stream{ipath.c_str()}; 660 cereal::JSONInputArchive iarchive(stream); 661 iarchive(modeData); 662 } 663 catch (const std::exception& e) 664 { 665 auto error = errno; 666 log<level::ERR>( 667 fmt::format("OccPersistData::load: failed to read {}, errno={}", 668 ipath.c_str(), error) 669 .c_str()); 670 modeData.modeInitialized = false; 671 modeData.ipsInitialized = false; 672 } 673 674 // print(); 675 } 676 677 // Called when PowerModeProperties defaults are available on DBus 678 void PowerMode::defaultsReady(sdbusplus::message::message& msg) 679 { 680 std::map<std::string, std::variant<std::string>> properties{}; 681 std::string interface; 682 msg.read(interface, properties); 683 684 // If persistent data exists, then don't need to read defaults 685 if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable())) 686 { 687 log<level::INFO>( 688 fmt::format( 689 "Default PowerModeProperties are now available (persistent modeAvail={}, ipsAvail={})", 690 persistedData.modeAvailable() ? 'y' : 'n', 691 persistedData.modeAvailable() ? 'y' : 'n') 692 .c_str()); 693 694 // Read default power mode defaults and update DBus 695 initPersistentData(); 696 } 697 } 698 699 // Get the default power mode from DBus and return true if success 700 bool PowerMode::getDefaultMode(SysPwrMode& defaultMode) 701 { 702 try 703 { 704 auto& bus = utils::getBus(); 705 std::string path = "/"; 706 std::string service = 707 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path); 708 auto method = 709 bus.new_method_call(service.c_str(), path.c_str(), 710 "org.freedesktop.DBus.Properties", "Get"); 711 method.append(PMODE_DEFAULT_INTERFACE, "PowerMode"); 712 auto reply = bus.call(method); 713 714 std::variant<std::string> stateEntryValue; 715 reply.read(stateEntryValue); 716 auto propVal = std::get<std::string>(stateEntryValue); 717 718 const std::string fullModeString = 719 PMODE_INTERFACE + ".PowerMode."s + propVal; 720 defaultMode = powermode::convertStringToMode(fullModeString); 721 if (!VALID_POWER_MODE_SETTING(defaultMode)) 722 { 723 log<level::ERR>( 724 fmt::format( 725 "PowerMode::getDefaultMode: Invalid default power mode found: {}", 726 defaultMode) 727 .c_str()); 728 // If default was read but not valid, use Max Performance 729 defaultMode = SysPwrMode::MAX_PERF; 730 return true; 731 } 732 } 733 catch (const sdbusplus::exception::exception& e) 734 { 735 log<level::ERR>( 736 fmt::format("Unable to read Default Power Mode: {}", e.what()) 737 .c_str()); 738 return false; 739 } 740 741 return true; 742 } 743 744 /* Get the default Idle Power Saver properties and return true if successful */ 745 bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil, 746 uint16_t& enterTime, uint8_t& exitUtil, 747 uint16_t& exitTime) 748 { 749 // Defaults: 750 ipsEnabled = true; // Enabled 751 enterUtil = 8; // Enter Utilization (8%) 752 enterTime = 240; // Enter Delay Time (240s) 753 exitUtil = 12; // Exit Utilization (12%) 754 exitTime = 10; // Exit Delay Time (10s) 755 756 std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>> 757 ipsProperties{}; 758 759 // Get all IPS properties from DBus 760 try 761 { 762 auto& bus = utils::getBus(); 763 std::string path = "/"; 764 std::string service = 765 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path); 766 auto method = 767 bus.new_method_call(service.c_str(), path.c_str(), 768 "org.freedesktop.DBus.Properties", "GetAll"); 769 method.append(PMODE_DEFAULT_INTERFACE); 770 auto reply = bus.call(method); 771 reply.read(ipsProperties); 772 } 773 catch (const sdbusplus::exception::exception& e) 774 { 775 log<level::ERR>( 776 fmt::format( 777 "Unable to read Default Idle Power Saver parameters so it will be disabled: {}", 778 e.what()) 779 .c_str()); 780 return false; 781 } 782 783 auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled"); 784 if (ipsEntry != ipsProperties.end()) 785 { 786 ipsEnabled = std::get<bool>(ipsEntry->second); 787 } 788 else 789 { 790 log<level::ERR>( 791 "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled"); 792 } 793 794 ipsEntry = ipsProperties.find("EnterUtilizationPercent"); 795 if (ipsEntry != ipsProperties.end()) 796 { 797 enterUtil = std::get<uint64_t>(ipsEntry->second); 798 } 799 else 800 { 801 log<level::ERR>( 802 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent"); 803 } 804 805 ipsEntry = ipsProperties.find("EnterUtilizationDwellTime"); 806 if (ipsEntry != ipsProperties.end()) 807 { 808 enterTime = std::get<uint64_t>(ipsEntry->second); 809 } 810 else 811 { 812 log<level::ERR>( 813 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime"); 814 } 815 816 ipsEntry = ipsProperties.find("ExitUtilizationPercent"); 817 if (ipsEntry != ipsProperties.end()) 818 { 819 exitUtil = std::get<uint64_t>(ipsEntry->second); 820 } 821 else 822 { 823 log<level::ERR>( 824 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent"); 825 } 826 827 ipsEntry = ipsProperties.find("ExitUtilizationDwellTime"); 828 if (ipsEntry != ipsProperties.end()) 829 { 830 exitTime = std::get<uint64_t>(ipsEntry->second); 831 } 832 else 833 { 834 log<level::ERR>( 835 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime"); 836 } 837 838 if (enterUtil > exitUtil) 839 { 840 log<level::ERR>( 841 fmt::format( 842 "ERROR: Default Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both", 843 enterUtil, exitUtil) 844 .c_str()); 845 enterUtil = exitUtil; 846 } 847 848 return true; 849 } 850 851 /* Read default IPS parameters, save them to the persistent file and update 852 DBus. Return true if successful */ 853 bool PowerMode::useDefaultIPSParms() 854 { 855 // Read the default IPS parameters 856 bool ipsEnabled; 857 uint8_t enterUtil, exitUtil; 858 uint16_t enterTime, exitTime; 859 if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, 860 exitTime)) 861 { 862 // Unable to read defaults 863 return false; 864 } 865 log<level::INFO>( 866 fmt::format( 867 "PowerMode::useDefaultIPSParms: Using default IPS parms: Enabled: {}, EnterUtil: {}%, EnterTime: {}s, ExitUtil: {}%, ExitTime: {}s", 868 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime) 869 .c_str()); 870 871 // Save IPS parms to the persistent file 872 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 873 exitTime); 874 875 // Write IPS parms to DBus 876 return updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 877 } 878 879 } // namespace powermode 880 881 } // namespace occ 882 883 } // namespace open_power 884