1 #include "powermode.hpp" 2 3 #include <fcntl.h> 4 #include <sys/ioctl.h> 5 6 #ifdef POWERVM_CHECK 7 #include <com/ibm/Host/Target/server.hpp> 8 #endif 9 #include <org/open_power/OCC/Device/error.hpp> 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 #include <xyz/openbmc_project/Common/error.hpp> 13 #include <xyz/openbmc_project/Control/Power/Mode/server.hpp> 14 15 #include <cassert> 16 #include <fstream> 17 #include <regex> 18 19 namespace open_power 20 { 21 namespace occ 22 { 23 namespace powermode 24 { 25 26 using namespace phosphor::logging; 27 using namespace std::literals::string_literals; 28 using namespace sdbusplus::org::open_power::OCC::Device::Error; 29 30 using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode; 31 32 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 33 34 // List of all Power Modes that are currently supported (and in Redfish) 35 #define VALID_POWER_MODE_SETTING(mode) \ 36 ((mode == SysPwrMode::STATIC) || (mode == SysPwrMode::POWER_SAVING) || \ 37 (mode == SysPwrMode::BALANCED_PERF) || (mode == SysPwrMode::MAX_PERF) || \ 38 (mode == SysPwrMode::EFF_FAVOR_POWER) || \ 39 (mode == SysPwrMode::EFF_FAVOR_PERF)) 40 // List of OEM Power Modes that are currently supported 41 #define VALID_OEM_POWER_MODE_SETTING(mode) \ 42 ((mode == SysPwrMode::SFP) || (mode == SysPwrMode::FFO) || \ 43 (mode == SysPwrMode::MAX_FREQ) || \ 44 (mode == SysPwrMode::NON_DETERMINISTIC)) 45 // List of all Power Modes that disable IPS 46 #define IS_ECO_MODE(mode) \ 47 ((mode == SysPwrMode::EFF_FAVOR_POWER) || \ 48 (mode == SysPwrMode::EFF_FAVOR_PERF)) 49 50 // Constructor 51 PowerMode::PowerMode(const Manager& managerRef, const char* modePath, 52 const char* ipsPath, EventPtr& event) : 53 ModeInterface(utils::getBus(), modePath, 54 ModeInterface::action::emit_no_signals), 55 manager(managerRef), 56 ipsMatch(utils::getBus(), 57 sdbusplus::bus::match::rules::propertiesChanged(PIPS_PATH, 58 PIPS_INTERFACE), 59 [this](auto& msg) { this->ipsChanged(msg); }), 60 defaultsUpdateMatch( 61 utils::getBus(), 62 sdbusplus::bus::match::rules::propertiesChangedNamespace( 63 "/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE), 64 [this](auto& msg) { this->defaultsReady(msg); }), 65 masterOccSet(false), masterActive(false), ipsObjectPath(ipsPath), 66 event(event) 67 { 68 // Get supported power modes from entity manager 69 if (false == getSupportedModes()) 70 { 71 // Did not find them so use default customer modes 72 using Mode = 73 sdbusplus::xyz::openbmc_project::Control::Power::server::Mode; 74 // Update power modes that will be allowed by the Redfish interface 75 ModeInterface::allowedPowerModes( 76 {Mode::PowerMode::Static, Mode::PowerMode::MaximumPerformance, 77 Mode::PowerMode::PowerSaving}); 78 } 79 80 SysPwrMode currentMode; 81 uint16_t oemModeData = 0; 82 // Read the persisted power mode 83 if (getMode(currentMode, oemModeData)) 84 { 85 // Validate persisted mode is supported 86 if (isValidMode(currentMode)) 87 { 88 // Update power mode on DBus and create IPS object if allowed 89 updateDbusMode(currentMode); 90 } 91 else 92 { 93 lg2::error("PowerMode: Persisted power mode ({MODE}/{DATA}) is not " 94 "valid. Reading system default mode", 95 "MODE", currentMode, "DATA", oemModeData); 96 persistedData.invalidateMode(); 97 // Read default power mode 98 initPersistentData(); 99 } 100 } 101 }; 102 103 void PowerMode::createIpsObject() 104 { 105 if (!ipsObject) 106 { 107 lg2::info("createIpsObject: Creating IPS object"); 108 ipsObject = 109 std::make_unique<IpsInterface>(utils::getBus(), ipsObjectPath); 110 111 uint8_t enterUtil, exitUtil; 112 uint16_t enterTime, exitTime; 113 bool ipsEnabled; 114 // Read the persisted Idle Power Saver parametres 115 if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)) 116 { 117 // Update Idle Power Saver parameters on DBus 118 updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 119 } 120 121 // Starts watching for IPS state changes. 122 addIpsWatch(true); 123 124 needToSendIpsData = true; 125 } 126 } 127 128 void PowerMode::removeIpsObject() 129 { 130 if (ipsObject) 131 { 132 // Stop watching for IPS state changes. 133 removeIpsWatch(); 134 135 lg2::info("removeIpsObject: Deleting IPS object"); 136 ipsObject.reset(nullptr); 137 } 138 needToSendIpsData = false; 139 } 140 141 // Set the Master OCC 142 void PowerMode::setMasterOcc(const std::string& masterOccPath) 143 { 144 if (masterOccSet) 145 { 146 if (masterOccPath != path) 147 { 148 lg2::error( 149 "PowerMode::setMasterOcc: Master changed (was OCC{INST}, {PATH})", 150 "INST", occInstance, "PATH", masterOccPath); 151 if (occCmd) 152 { 153 occCmd.reset(); 154 } 155 } 156 } 157 path = masterOccPath; 158 occInstance = path.back() - '0'; 159 lg2::debug("PowerMode::setMasterOcc(OCC{INST}, {PATH})", "INST", 160 occInstance, "PATH", path); 161 if (!occCmd) 162 { 163 occCmd = std::make_unique<open_power::occ::OccCommand>( 164 occInstance, path.c_str()); 165 } 166 masterOccSet = true; 167 }; 168 169 // Set the state of power mode lock. Writing persistent data via dbus method. 170 bool PowerMode::powerModeLock() 171 { 172 lg2::info("PowerMode::powerModeLock: locking mode change"); 173 persistedData.updateModeLock(true); // write persistent data 174 return true; 175 } 176 177 // Get the state of power mode. Reading persistent data via dbus method. 178 bool PowerMode::powerModeLockStatus() 179 { 180 bool status = persistedData.getModeLock(); // read persistent data 181 lg2::info("PowerMode::powerModeLockStatus: {STATUS}", "STATUS", 182 status ? "locked" : "unlocked"); 183 return status; 184 } 185 186 // Called from OCC PassThrough interface (via CE login / BMC command line) 187 bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t oemModeData) 188 { 189 if (persistedData.getModeLock()) 190 { 191 lg2::info("PowerMode::setMode: mode change blocked"); 192 return false; 193 } 194 195 if (updateDbusMode(newMode) == false) 196 { 197 // Unsupported mode 198 return false; 199 } 200 201 // Save mode 202 persistedData.updateMode(newMode, oemModeData); 203 204 // Send mode change to OCC 205 if (sendModeChange() != CmdStatus::SUCCESS) 206 { 207 // Mode change failed 208 return false; 209 } 210 211 return true; 212 } 213 214 // Convert PowerMode value to occ-control internal SysPwrMode 215 // Returns SysPwrMode::NO_CHANGE if mode not valid 216 SysPwrMode getInternalMode(const Mode::PowerMode& mode) 217 { 218 if (mode == Mode::PowerMode::MaximumPerformance) 219 { 220 return SysPwrMode::MAX_PERF; 221 } 222 else if (mode == Mode::PowerMode::PowerSaving) 223 { 224 return SysPwrMode::POWER_SAVING; 225 } 226 else if (mode == Mode::PowerMode::Static) 227 { 228 return SysPwrMode::STATIC; 229 } 230 else if (mode == Mode::PowerMode::EfficiencyFavorPower) 231 { 232 return SysPwrMode::EFF_FAVOR_POWER; 233 } 234 else if (mode == Mode::PowerMode::EfficiencyFavorPerformance) 235 { 236 return SysPwrMode::EFF_FAVOR_PERF; 237 } 238 else if (mode == Mode::PowerMode::BalancedPerformance) 239 { 240 return SysPwrMode::BALANCED_PERF; 241 } 242 243 lg2::warning("getInternalMode: Invalid PowerMode specified"); 244 return SysPwrMode::NO_CHANGE; 245 } 246 247 // Convert PowerMode string to OCC SysPwrMode 248 // Returns NO_CHANGE if OEM or unsupported mode 249 SysPwrMode convertStringToMode(const std::string& i_modeString) 250 { 251 SysPwrMode newMode = SysPwrMode::NO_CHANGE; 252 try 253 { 254 Mode::PowerMode newPMode = 255 Mode::convertPowerModeFromString(i_modeString); 256 newMode = getInternalMode(newPMode); 257 } 258 catch (const std::exception& e) 259 { 260 // Strip off prefix to to search OEM modes not part of Redfish 261 auto prefix = PMODE_INTERFACE + ".PowerMode."s; 262 std::string shortMode = i_modeString; 263 std::string::size_type index = i_modeString.find(prefix); 264 if (index != std::string::npos) 265 { 266 shortMode.erase(0, prefix.length()); 267 } 268 if (shortMode == "FFO") 269 { 270 newMode = SysPwrMode::FFO; 271 } 272 else if (shortMode == "SFP") 273 { 274 newMode = SysPwrMode::SFP; 275 } 276 else if (shortMode == "MaxFrequency") 277 { 278 newMode = SysPwrMode::MAX_FREQ; 279 } 280 else if (shortMode == "NonDeterministic") 281 { 282 newMode = SysPwrMode::NON_DETERMINISTIC; 283 } 284 else 285 { 286 lg2::error( 287 "convertStringToMode: Invalid Power Mode: {MODE} ({DATA})", 288 "MODE", shortMode, "DATA", e.what()); 289 } 290 } 291 return newMode; 292 } 293 294 // Check if Hypervisor target is PowerVM 295 bool isPowerVM() 296 { 297 bool powerVmTarget = true; 298 #ifdef POWERVM_CHECK 299 namespace Hyper = sdbusplus::com::ibm::Host::server; 300 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor"; 301 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target"; 302 constexpr auto HYPE_PROP = "Target"; 303 304 // This will throw exception on failure 305 auto& bus = utils::getBus(); 306 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE); 307 auto method = bus.new_method_call(service.c_str(), HYPE_PATH, 308 "org.freedesktop.DBus.Properties", "Get"); 309 method.append(HYPE_INTERFACE, HYPE_PROP); 310 auto reply = bus.call(method); 311 312 std::variant<std::string> hyperEntryValue; 313 reply.read(hyperEntryValue); 314 auto propVal = std::get<std::string>(hyperEntryValue); 315 if (Hyper::Target::convertHypervisorFromString(propVal) == 316 Hyper::Target::Hypervisor::PowerVM) 317 { 318 powerVmTarget = true; 319 } 320 321 lg2::debug("isPowerVM returning {VAL}", "VAL", powerVmTarget); 322 #endif 323 324 return powerVmTarget; 325 } 326 327 // Initialize persistent data and return true if successful 328 bool PowerMode::initPersistentData() 329 { 330 if (!persistedData.modeAvailable()) 331 { 332 // Read the default mode 333 SysPwrMode currentMode; 334 if (!getDefaultMode(currentMode)) 335 { 336 // Unable to read defaults 337 return false; 338 } 339 lg2::info("PowerMode::initPersistentData: Using default mode: {MODE}", 340 "MODE", currentMode); 341 342 // Save default mode as current mode 343 persistedData.updateMode(currentMode, 0); 344 345 // Write default mode to DBus and create IPS object if allowed 346 updateDbusMode(currentMode); 347 } 348 349 if (!persistedData.ipsAvailable()) 350 { 351 // Read the default IPS parameters, write persistent file and update 352 // DBus 353 return useDefaultIPSParms(); 354 } 355 return true; 356 } 357 358 // Get the requested power mode and return true if successful 359 bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData) 360 { 361 currentMode = SysPwrMode::NO_CHANGE; 362 oemModeData = 0; 363 364 if (!persistedData.getMode(currentMode, oemModeData)) 365 { 366 // Persistent data not initialized, read defaults and update DBus 367 if (!initPersistentData()) 368 { 369 // Unable to read defaults from entity manager yet 370 return false; 371 } 372 return persistedData.getMode(currentMode, oemModeData); 373 } 374 375 return true; 376 } 377 378 // Set the power mode on DBus and create IPS object if allowed/needed 379 bool PowerMode::updateDbusMode(const SysPwrMode newMode) 380 { 381 if (!isValidMode(newMode)) 382 { 383 lg2::error( 384 "PowerMode::updateDbusMode - Requested power mode not supported: {MODE}", 385 "MODE", newMode); 386 return false; 387 } 388 389 ModeInterface::PowerMode dBusMode = Mode::PowerMode::OEM; 390 if (customerModeList.contains(newMode)) 391 { 392 // Convert mode for DBus 393 switch (newMode) 394 { 395 case SysPwrMode::STATIC: 396 dBusMode = Mode::PowerMode::Static; 397 break; 398 case SysPwrMode::POWER_SAVING: 399 dBusMode = Mode::PowerMode::PowerSaving; 400 break; 401 case SysPwrMode::MAX_PERF: 402 dBusMode = Mode::PowerMode::MaximumPerformance; 403 break; 404 case SysPwrMode::EFF_FAVOR_POWER: 405 dBusMode = Mode::PowerMode::EfficiencyFavorPower; 406 break; 407 case SysPwrMode::EFF_FAVOR_PERF: 408 dBusMode = Mode::PowerMode::EfficiencyFavorPerformance; 409 break; 410 case SysPwrMode::BALANCED_PERF: 411 dBusMode = Mode::PowerMode::BalancedPerformance; 412 break; 413 default: 414 break; 415 } 416 } 417 // else return OEM mode 418 419 // Determine if IPS is allowed and create/remove as needed 420 if (IS_ECO_MODE(newMode)) 421 { 422 removeIpsObject(); 423 } 424 else 425 { 426 createIpsObject(); 427 } 428 429 ModeInterface::powerMode(dBusMode); 430 431 return true; 432 } 433 434 // Send mode change request to the master OCC 435 CmdStatus PowerMode::sendModeChange() 436 { 437 CmdStatus status; 438 439 SysPwrMode newMode; 440 uint16_t oemModeData = 0; 441 getMode(newMode, oemModeData); 442 443 if (isValidMode(newMode)) 444 { 445 if (IS_ECO_MODE(newMode)) 446 { 447 // Customer no longer able to enable IPS 448 removeIpsObject(); 449 } 450 else 451 { 452 // Customer now able to enable IPS 453 if (!ipsObject) 454 { 455 createIpsObject(); 456 } 457 } 458 459 if (!masterActive || !masterOccSet) 460 { 461 // Nothing to do until OCC goes active 462 lg2::debug("PowerMode::sendModeChange: OCC master not active"); 463 return CmdStatus::SUCCESS; 464 } 465 466 if (!isPowerVM()) 467 { 468 // Mode change is only supported on PowerVM systems 469 lg2::debug( 470 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems"); 471 return CmdStatus::SUCCESS; 472 } 473 474 std::vector<std::uint8_t> cmd, rsp; 475 cmd.reserve(9); 476 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE)); 477 cmd.push_back(0x00); // Data Length (2 bytes) 478 cmd.push_back(0x06); 479 cmd.push_back(0x30); // Data (Version) 480 cmd.push_back(uint8_t(OccState::NO_CHANGE)); 481 cmd.push_back(uint8_t(newMode)); 482 cmd.push_back(oemModeData >> 8); // Mode Data (Freq Point) 483 cmd.push_back(oemModeData & 0xFF); // 484 cmd.push_back(0x00); // reserved 485 lg2::info( 486 "PowerMode::sendModeChange: SET_MODE({MODE},{DATA}) command to OCC{INST} ({LEN} bytes)", 487 "MODE", uint8_t(newMode), "DATA", oemModeData, "INST", occInstance, 488 "LEN", cmd.size()); 489 status = occCmd->send(cmd, rsp); 490 if (status == CmdStatus::SUCCESS) 491 { 492 if (rsp.size() == 5) 493 { 494 if (RspStatus::SUCCESS == RspStatus(rsp[2])) 495 { 496 if (needToSendIpsData) 497 { 498 // Successful mode change and IPS is now allowed, so 499 // send IPS config 500 sendIpsData(); 501 } 502 } 503 else 504 { 505 lg2::error( 506 "PowerMode::sendModeChange: SET MODE failed with status {STATUS}", 507 "STATUS", lg2::hex, rsp[2]); 508 dump_hex(rsp); 509 status = CmdStatus::FAILURE; 510 } 511 } 512 else 513 { 514 lg2::error( 515 "PowerMode::sendModeChange: INVALID SET MODE response"); 516 dump_hex(rsp); 517 status = CmdStatus::FAILURE; 518 } 519 } 520 else 521 { 522 lg2::error( 523 "PowerMode::sendModeChange: SET_MODE FAILED with status={STATUS}", 524 "STATUS", lg2::hex, uint8_t(status)); 525 } 526 } 527 else 528 { 529 lg2::error( 530 "PowerMode::sendModeChange: Unable to set power mode to {MODE}", 531 "MODE", newMode); 532 status = CmdStatus::FAILURE; 533 } 534 535 return status; 536 } 537 538 // Handle IPS changed event (from GUI/Redfish) 539 void PowerMode::ipsChanged(sdbusplus::message_t& msg) 540 { 541 bool parmsChanged = false; 542 std::string interface; 543 std::map<std::string, std::variant<bool, uint8_t, uint64_t>> 544 ipsProperties{}; 545 msg.read(interface, ipsProperties); 546 547 // Read persisted values 548 bool ipsEnabled; 549 uint8_t enterUtil, exitUtil; 550 uint16_t enterTime, exitTime; 551 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 552 553 if (!ipsObject) 554 { 555 lg2::warning( 556 "ipsChanged: Idle Power Saver can not be modified in an ECO power mode"); 557 return; 558 } 559 560 // Check for any changed data 561 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP); 562 if (ipsEntry != ipsProperties.end()) 563 { 564 ipsEnabled = std::get<bool>(ipsEntry->second); 565 lg2::info("Idle Power Saver change: Enabled={STAT}", "STAT", 566 ipsEnabled); 567 parmsChanged = true; 568 } 569 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL); 570 if (ipsEntry != ipsProperties.end()) 571 { 572 enterUtil = std::get<uint8_t>(ipsEntry->second); 573 lg2::info("Idle Power Saver change: Enter Util={UTIL}%", "UTIL", 574 enterUtil); 575 parmsChanged = true; 576 } 577 ipsEntry = ipsProperties.find(IPS_ENTER_TIME); 578 if (ipsEntry != ipsProperties.end()) 579 { 580 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second)); 581 enterTime = 582 std::chrono::duration_cast<std::chrono::seconds>(ms).count(); 583 lg2::info("Idle Power Saver change: Enter Time={TIME}sec", "TIME", 584 enterTime); 585 parmsChanged = true; 586 } 587 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL); 588 if (ipsEntry != ipsProperties.end()) 589 { 590 exitUtil = std::get<uint8_t>(ipsEntry->second); 591 lg2::info("Idle Power Saver change: Exit Util={UTIL}%", "UTIL", 592 exitUtil); 593 parmsChanged = true; 594 } 595 ipsEntry = ipsProperties.find(IPS_EXIT_TIME); 596 if (ipsEntry != ipsProperties.end()) 597 { 598 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second)); 599 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count(); 600 lg2::info("Idle Power Saver change: Exit Time={TIME}sec", "TIME", 601 exitTime); 602 parmsChanged = true; 603 } 604 605 if (parmsChanged) 606 { 607 if (exitUtil == 0) 608 { 609 // Setting the exitUtil to 0 will force restoring the default IPS 610 // parmeters (0 is not valid exit utilization) 611 lg2::info( 612 "Idle Power Saver Exit Utilization is 0%. Restoring default parameters"); 613 // Read the default IPS parameters, write persistent file and update 614 // DBus 615 useDefaultIPSParms(); 616 } 617 else 618 { 619 // Update persistant data with new DBus values 620 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 621 exitTime); 622 } 623 624 // Trigger IPS data to get sent to the OCC 625 sendIpsData(); 626 } 627 628 return; 629 } 630 631 /** @brief Get the Idle Power Saver properties from persisted data 632 * @return true if IPS parameters were read 633 */ 634 bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil, 635 uint16_t& enterTime, uint8_t& exitUtil, 636 uint16_t& exitTime) 637 { 638 // Defaults: 639 ipsEnabled = true; // Enabled 640 enterUtil = 8; // Enter Utilization (8%) 641 enterTime = 240; // Enter Delay Time (240s) 642 exitUtil = 12; // Exit Utilization (12%) 643 exitTime = 10; // Exit Delay Time (10s) 644 645 if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 646 exitTime)) 647 { 648 // Persistent data not initialized, read defaults and update DBus 649 if (!initPersistentData()) 650 { 651 // Unable to read defaults from entity manager yet 652 return false; 653 } 654 655 persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 656 exitTime); 657 } 658 659 if (enterUtil > exitUtil) 660 { 661 lg2::error( 662 "ERROR: Idle Power Saver Enter Utilization ({ENTER}%) is > Exit Utilization ({EXIT}%) - using Exit for both", 663 "ENTER", enterUtil, "EXIT", exitUtil); 664 enterUtil = exitUtil; 665 } 666 667 return true; 668 } 669 670 // Set the Idle Power Saver data on DBus 671 bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil, 672 const uint16_t enterTime, const uint8_t exitUtil, 673 const uint16_t exitTime) 674 { 675 if (ipsObject) 676 { 677 // true = skip update signal 678 ipsObject->setPropertyByName(IPS_ENABLED_PROP, enabled, true); 679 ipsObject->setPropertyByName(IPS_ENTER_UTIL, enterUtil, true); 680 // Convert time from seconds to ms 681 uint64_t msTime = enterTime * 1000; 682 ipsObject->setPropertyByName(IPS_ENTER_TIME, msTime, true); 683 ipsObject->setPropertyByName(IPS_EXIT_UTIL, exitUtil, true); 684 msTime = exitTime * 1000; 685 ipsObject->setPropertyByName(IPS_EXIT_TIME, msTime, true); 686 } 687 else 688 { 689 lg2::warning("updateDbusIPS: No IPS object was found"); 690 } 691 692 return true; 693 } 694 695 // Send Idle Power Saver config data to the master OCC 696 CmdStatus PowerMode::sendIpsData() 697 { 698 if (!masterActive || !masterOccSet) 699 { 700 // Nothing to do 701 return CmdStatus::SUCCESS; 702 } 703 704 if (!isPowerVM()) 705 { 706 // Idle Power Saver data is only supported on PowerVM systems 707 lg2::debug( 708 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems"); 709 return CmdStatus::SUCCESS; 710 } 711 712 if (!ipsObject) 713 { 714 // Idle Power Saver data is not available in Eco Modes 715 lg2::info( 716 "PowerMode::sendIpsData: Skipping IPS data due to being in an ECO Power Mode"); 717 return CmdStatus::SUCCESS; 718 } 719 720 bool ipsEnabled; 721 uint8_t enterUtil, exitUtil; 722 uint16_t enterTime, exitTime; 723 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 724 725 lg2::info( 726 "Idle Power Saver Parameters: enabled:{ENABLE}, enter:{EUTIL}%/{ETIME}s, exit:{XUTIL}%/{XTIME}s", 727 "ENABLE", ipsEnabled, "EUTIL", enterUtil, "ETIME", enterTime, "XUTIL", 728 exitUtil, "XTIME", exitTime); 729 730 std::vector<std::uint8_t> cmd, rsp; 731 cmd.reserve(12); 732 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA)); 733 cmd.push_back(0x00); // Data Length (2 bytes) 734 cmd.push_back(0x09); // 735 cmd.push_back(0x11); // Config Format: IPS Settings 736 cmd.push_back(0x00); // Version 737 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable 738 cmd.push_back(enterTime >> 8); // Enter Delay Time 739 cmd.push_back(enterTime & 0xFF); // 740 cmd.push_back(enterUtil); // Enter Utilization 741 cmd.push_back(exitTime >> 8); // Exit Delay Time 742 cmd.push_back(exitTime & 0xFF); // 743 cmd.push_back(exitUtil); // Exit Utilization 744 lg2::info("PowerMode::sendIpsData: SET_CFG_DATA[IPS] " 745 "command to OCC{INST} ({LEN} bytes)", 746 "INST", occInstance, "LEN", cmd.size()); 747 CmdStatus status = occCmd->send(cmd, rsp); 748 if (status == CmdStatus::SUCCESS) 749 { 750 if (rsp.size() == 5) 751 { 752 if (RspStatus::SUCCESS == RspStatus(rsp[2])) 753 { 754 needToSendIpsData = false; 755 } 756 else 757 { 758 lg2::error( 759 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status {STATUS}", 760 "STATUS", lg2::hex, rsp[2]); 761 dump_hex(rsp); 762 status = CmdStatus::FAILURE; 763 } 764 } 765 else 766 { 767 lg2::error( 768 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response"); 769 dump_hex(rsp); 770 status = CmdStatus::FAILURE; 771 } 772 } 773 else 774 { 775 lg2::error( 776 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] with status={STATUS}", 777 "STATUS", lg2::hex, uint8_t(status)); 778 } 779 780 return status; 781 } 782 783 // Print the current values 784 void OccPersistData::print() 785 { 786 if (modeData.modeInitialized) 787 { 788 lg2::info( 789 "OccPersistData: Mode: {MODE}, OEM Mode Data: {DATA} ({DATAHEX} Locked{LOCK})", 790 "MODE", lg2::hex, uint8_t(modeData.mode), "DATA", 791 modeData.oemModeData, "DATAHEX", lg2::hex, modeData.oemModeData, 792 "LOCK", modeData.modeLocked); 793 } 794 if (modeData.ipsInitialized) 795 { 796 lg2::info( 797 "OccPersistData: IPS enabled:{ENABLE}, enter:{EUTIL}%/{ETIME}s, exit:{XUTIL}%/{XTIME}s", 798 "ENABLE", modeData.ipsEnabled, "EUTIL", modeData.ipsEnterUtil, 799 "ETIME", modeData.ipsEnterTime, "XUTIL", modeData.ipsExitUtil, 800 "XTIME", modeData.ipsExitTime); 801 } 802 } 803 804 // Saves the OEM mode data in the filesystem using cereal. 805 void OccPersistData::save() 806 { 807 std::filesystem::path opath = 808 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename; 809 810 if (!std::filesystem::exists(opath.parent_path())) 811 { 812 std::filesystem::create_directory(opath.parent_path()); 813 } 814 815 lg2::debug( 816 "OccPersistData::save: Writing Power Mode persisted data to {FILE}", 817 "FILE", opath); 818 // print(); 819 820 std::ofstream stream{opath.c_str()}; 821 cereal::JSONOutputArchive oarchive{stream}; 822 823 oarchive(modeData); 824 } 825 826 // Loads the OEM mode data in the filesystem using cereal. 827 void OccPersistData::load() 828 { 829 std::filesystem::path ipath = 830 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename; 831 832 if (!std::filesystem::exists(ipath)) 833 { 834 modeData.modeInitialized = false; 835 modeData.ipsInitialized = false; 836 return; 837 } 838 839 lg2::debug( 840 "OccPersistData::load: Reading Power Mode persisted data from {FILE}", 841 "FILE", ipath); 842 try 843 { 844 std::ifstream stream{ipath.c_str()}; 845 cereal::JSONInputArchive iarchive(stream); 846 iarchive(modeData); 847 } 848 catch (const std::exception& e) 849 { 850 auto error = errno; 851 lg2::error("OccPersistData::load: failed to read {FILE}, errno={ERR}", 852 "FILE", ipath, "ERR", error); 853 modeData.modeInitialized = false; 854 modeData.ipsInitialized = false; 855 } 856 857 // print(); 858 } 859 860 // Called when PowerModeProperties defaults are available on DBus 861 void PowerMode::defaultsReady(sdbusplus::message_t& msg) 862 { 863 std::map<std::string, std::variant<std::string>> properties{}; 864 std::string interface; 865 msg.read(interface, properties); 866 867 if (persistedData.modeAvailable()) 868 { 869 // Validate persisted mode is supported 870 SysPwrMode pMode = SysPwrMode::NO_CHANGE; 871 uint16_t oemModeData = 0; 872 persistedData.getMode(pMode, oemModeData); 873 if (!isValidMode(pMode)) 874 { 875 lg2::error( 876 "defaultsReady: Persisted power mode ({MODE}/{DATA}) is not valid. Reading system default mode", 877 "MODE", pMode, "DATA", oemModeData); 878 persistedData.invalidateMode(); 879 } 880 } 881 882 // If persistent data exists, then don't need to read defaults 883 if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable())) 884 { 885 lg2::info( 886 "Default PowerModeProperties are now available (persistent modeAvail={MAVAIL}, ipsAvail={IAVAIL})", 887 "MAVAIL", persistedData.modeAvailable(), "IAVAIL", 888 persistedData.ipsAvailable()); 889 890 // Read default power mode defaults and update DBus 891 initPersistentData(); 892 } 893 } 894 895 // Get the default power mode from DBus and return true if success 896 bool PowerMode::getDefaultMode(SysPwrMode& defaultMode) 897 { 898 try 899 { 900 auto& bus = utils::getBus(); 901 std::string path = "/"; 902 std::string service = 903 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path); 904 auto method = 905 bus.new_method_call(service.c_str(), path.c_str(), 906 "org.freedesktop.DBus.Properties", "Get"); 907 method.append(PMODE_DEFAULT_INTERFACE, "PowerMode"); 908 auto reply = bus.call(method); 909 910 std::variant<std::string> stateEntryValue; 911 reply.read(stateEntryValue); 912 auto propVal = std::get<std::string>(stateEntryValue); 913 914 const std::string fullModeString = 915 PMODE_INTERFACE + ".PowerMode."s + propVal; 916 defaultMode = powermode::convertStringToMode(fullModeString); 917 if (!VALID_POWER_MODE_SETTING(defaultMode)) 918 { 919 lg2::error("PowerMode::getDefaultMode: Invalid " 920 "default power mode found: {MODE}", 921 "MODE", defaultMode); 922 // If default was read but not valid, use Max Performance 923 defaultMode = SysPwrMode::MAX_PERF; 924 return true; 925 } 926 } 927 catch (const sdbusplus::exception_t& e) 928 { 929 lg2::error("Unable to read Default Power Mode: {ERR}", "ERR", e.what()); 930 return false; 931 } 932 933 return true; 934 } 935 936 /* Get the default Idle Power Saver properties and return true if successful */ 937 bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil, 938 uint16_t& enterTime, uint8_t& exitUtil, 939 uint16_t& exitTime) 940 { 941 // Defaults: 942 ipsEnabled = true; // Enabled 943 enterUtil = 8; // Enter Utilization (8%) 944 enterTime = 240; // Enter Delay Time (240s) 945 exitUtil = 12; // Exit Utilization (12%) 946 exitTime = 10; // Exit Delay Time (10s) 947 948 std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>> 949 ipsProperties{}; 950 951 // Get all IPS properties from DBus 952 try 953 { 954 auto& bus = utils::getBus(); 955 std::string path = "/"; 956 std::string service = 957 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path); 958 auto method = 959 bus.new_method_call(service.c_str(), path.c_str(), 960 "org.freedesktop.DBus.Properties", "GetAll"); 961 method.append(PMODE_DEFAULT_INTERFACE); 962 auto reply = bus.call(method); 963 reply.read(ipsProperties); 964 } 965 catch (const sdbusplus::exception_t& e) 966 { 967 lg2::error( 968 "Unable to read Default Idle Power Saver parameters so it will be disabled: {ERR}", 969 "ERR", e.what()); 970 return false; 971 } 972 973 auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled"); 974 if (ipsEntry != ipsProperties.end()) 975 { 976 ipsEnabled = std::get<bool>(ipsEntry->second); 977 } 978 else 979 { 980 lg2::error( 981 "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled"); 982 } 983 984 ipsEntry = ipsProperties.find("EnterUtilizationPercent"); 985 if (ipsEntry != ipsProperties.end()) 986 { 987 enterUtil = std::get<uint64_t>(ipsEntry->second); 988 } 989 else 990 { 991 lg2::error( 992 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent"); 993 } 994 995 ipsEntry = ipsProperties.find("EnterUtilizationDwellTime"); 996 if (ipsEntry != ipsProperties.end()) 997 { 998 enterTime = std::get<uint64_t>(ipsEntry->second); 999 } 1000 else 1001 { 1002 lg2::error( 1003 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime"); 1004 } 1005 1006 ipsEntry = ipsProperties.find("ExitUtilizationPercent"); 1007 if (ipsEntry != ipsProperties.end()) 1008 { 1009 exitUtil = std::get<uint64_t>(ipsEntry->second); 1010 } 1011 else 1012 { 1013 lg2::error( 1014 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent"); 1015 } 1016 1017 ipsEntry = ipsProperties.find("ExitUtilizationDwellTime"); 1018 if (ipsEntry != ipsProperties.end()) 1019 { 1020 exitTime = std::get<uint64_t>(ipsEntry->second); 1021 } 1022 else 1023 { 1024 lg2::error( 1025 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime"); 1026 } 1027 1028 if (enterUtil > exitUtil) 1029 { 1030 lg2::error( 1031 "ERROR: Default Idle Power Saver Enter Utilization ({ENTER}%) is > Exit Utilization ({EXIT}%) - using Exit for both", 1032 "ENTER", enterUtil, "EXIT", exitUtil); 1033 enterUtil = exitUtil; 1034 } 1035 1036 return true; 1037 } 1038 1039 /* Read default IPS parameters, save them to the persistent file and update 1040 DBus. Return true if successful */ 1041 bool PowerMode::useDefaultIPSParms() 1042 { 1043 // Read the default IPS parameters 1044 bool ipsEnabled; 1045 uint8_t enterUtil, exitUtil; 1046 uint16_t enterTime, exitTime; 1047 if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, 1048 exitTime)) 1049 { 1050 // Unable to read defaults 1051 return false; 1052 } 1053 lg2::info("PowerMode::useDefaultIPSParms: Using default IPS parms: " 1054 "Enabled: {ENABLE}, EnterUtil: {EUTIL}%, EnterTime: {ETIME}s, " 1055 "ExitUtil: {XUTIL}%, ExitTime: {XTIME}s", 1056 "ENABLE", ipsEnabled, "EUTIL", enterUtil, "ETIME", enterTime, 1057 "XUTIL", exitUtil, "XTIME", exitTime); 1058 1059 // Save IPS parms to the persistent file 1060 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil, 1061 exitTime); 1062 1063 // Write IPS parms to DBus 1064 return updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime); 1065 } 1066 1067 // Starts to watch for IPS active state changes. 1068 bool PowerMode::openIpsFile() 1069 { 1070 bool rc = true; 1071 fd = open(ipsStatusFile.c_str(), O_RDONLY | O_NONBLOCK); 1072 const int open_errno = errno; 1073 if (fd < 0) 1074 { 1075 lg2::error("openIpsFile Error({ERR})={STR} : File={FILE}", "ERR", 1076 open_errno, "STR", strerror(open_errno), "FILE", 1077 ipsStatusFile); 1078 1079 close(fd); 1080 1081 using namespace sdbusplus::org::open_power::OCC::Device::Error; 1082 report<OpenFailure>( 1083 phosphor::logging::org::open_power::OCC::Device::OpenFailure:: 1084 CALLOUT_ERRNO(open_errno), 1085 phosphor::logging::org::open_power::OCC::Device::OpenFailure:: 1086 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str())); 1087 1088 // We are no longer watching the error 1089 if (ipsObject) 1090 { 1091 ipsObject->active(false); 1092 } 1093 1094 watching = false; 1095 rc = false; 1096 // NOTE: this will leave the system not reporting IPS active state to 1097 // Fan Controls, Until an APP reload, or IPL and we will attempt again. 1098 } 1099 return rc; 1100 } 1101 1102 // Starts to watch for IPS active state changes. 1103 void PowerMode::addIpsWatch(bool poll) 1104 { 1105 // open file and register callback on file if we are not currently watching, 1106 // and if poll=true, and if we are the master. 1107 if ((!watching) && poll) 1108 { 1109 // Open the file 1110 if (openIpsFile()) 1111 { 1112 // register the callback handler which sets 'watching' 1113 registerIpsStatusCallBack(); 1114 } 1115 } 1116 } 1117 1118 // Stops watching for IPS active state changes. 1119 void PowerMode::removeIpsWatch() 1120 { 1121 // NOTE: we want to remove event, close file, and IPS active false no 1122 // matter what the 'watching' flags is set to. 1123 1124 // We are no longer watching the error 1125 if (ipsObject) 1126 { 1127 ipsObject->active(false); 1128 } 1129 1130 watching = false; 1131 1132 // Close file 1133 close(fd); 1134 1135 // clears sourcePtr in the event source. 1136 eventSource.reset(); 1137 } 1138 1139 // Attaches the FD to event loop and registers the callback handler 1140 void PowerMode::registerIpsStatusCallBack() 1141 { 1142 decltype(eventSource.get()) sourcePtr = nullptr; 1143 1144 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR, 1145 ipsStatusCallBack, this); 1146 if (r < 0) 1147 { 1148 lg2::error("sd_event_add_io: Error({ERR})={STR} : File={FILE}", "ERR", 1149 r, "STR", strerror(-r), "FILE", ipsStatusFile); 1150 1151 using InternalFailure = 1152 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 1153 report<InternalFailure>(); 1154 1155 removeIpsWatch(); 1156 // NOTE: this will leave the system not reporting IPS active state to 1157 // Fan Controls, Until an APP reload, or IPL and we will attempt again. 1158 } 1159 else 1160 { 1161 // puts sourcePtr in the event source. 1162 eventSource.reset(sourcePtr); 1163 // Set we are watching the error 1164 watching = true; 1165 } 1166 } 1167 1168 // Static function to redirect to non static analyze event function to be 1169 // able to read file and push onto dBus. 1170 int PowerMode::ipsStatusCallBack(sd_event_source* /*es*/, int /*fd*/, 1171 uint32_t /*revents*/, void* userData) 1172 { 1173 auto pmode = static_cast<PowerMode*>(userData); 1174 pmode->analyzeIpsEvent(); 1175 return 0; 1176 } 1177 1178 // Function to Read SysFs file change on IPS state and push on dBus. 1179 void PowerMode::analyzeIpsEvent() 1180 { 1181 // Need to seek to START, else the poll returns immediately telling 1182 // there is data to be read. if not done this floods the system. 1183 auto r = lseek(fd, 0, SEEK_SET); 1184 const int open_errno = errno; 1185 if (r < 0) 1186 { 1187 // NOTE: upon file access error we can not just re-open file, we have to 1188 // remove and add to watch. 1189 removeIpsWatch(); 1190 addIpsWatch(true); 1191 } 1192 1193 // if we are 'watching' that is the file seek, or the re-open passed.. we 1194 // can read the data 1195 if (watching) 1196 { 1197 // This file gets created when polling OCCs. A value or length of 0 is 1198 // deemed success. That means we would disable IPS active on dbus. 1199 char data; 1200 bool ipsState = false; 1201 const auto len = read(fd, &data, sizeof(data)); 1202 const int readErrno = errno; 1203 if (len <= 0) 1204 { 1205 removeIpsWatch(); 1206 1207 lg2::error( 1208 "IPS state Read Error({ERR})={STR} : File={FILE} : len={LEN}", 1209 "ERR", readErrno, "STR", strerror(readErrno), "FILE", 1210 ipsStatusFile, "LEN", len); 1211 1212 report<ReadFailure>( 1213 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 1214 CALLOUT_ERRNO(readErrno), 1215 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 1216 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str())); 1217 1218 // NOTE: this will leave the system not reporting IPS active state 1219 // to Fan Controls, Until an APP reload, or IPL and we will attempt 1220 // again. 1221 } 1222 else 1223 { 1224 // Data returned in ASCII. 1225 // convert to integer. atoi() 1226 // from OCC_P10_FW_Interfaces spec 1227 // Bit 6: IPS active 1 indicates enabled. 1228 // Bit 7: IPS enabled. 1 indicates enabled. 1229 // mask off bit 6 --> & 0x02 1230 // Shift left one bit and store as bool. >> 1 1231 ipsState = static_cast<bool>(((atoi(&data)) & 0x2) >> 1); 1232 } 1233 1234 // This will only set IPS active dbus if different than current. 1235 if (ipsObject) 1236 { 1237 ipsObject->active(ipsState); 1238 } 1239 } 1240 else 1241 { 1242 removeIpsWatch(); 1243 1244 // If the Retry did not get to "watching = true" we already have an 1245 // error log, just post trace. 1246 lg2::error("Retry on File seek Error({ERR})={STR} : File={FILE}", "ERR", 1247 open_errno, "STR", strerror(open_errno), "FILE", 1248 ipsStatusFile); 1249 1250 // NOTE: this will leave the system not reporting IPS active state to 1251 // Fan Controls, Until an APP reload, or IPL and we will attempt again. 1252 } 1253 1254 return; 1255 } 1256 1257 // overrides read/write to powerMode dbus property. 1258 Mode::PowerMode PowerMode::powerMode(Mode::PowerMode requestedMode) 1259 { 1260 if (persistedData.getModeLock()) 1261 { 1262 lg2::info("PowerMode::powerMode: mode property change blocked"); 1263 elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON( 1264 "mode change not allowed due to lock")); 1265 } 1266 else 1267 { 1268 // Verify requested mode is allowed 1269 1270 // Convert PowerMode to internal SysPwrMode 1271 SysPwrMode newMode = getInternalMode(requestedMode); 1272 if (newMode != SysPwrMode::NO_CHANGE) 1273 { 1274 // Validate it is an allowed customer mode 1275 if (customerModeList.contains(newMode)) 1276 { 1277 // Update persisted data with new mode 1278 persistedData.updateMode(newMode, 0); 1279 1280 lg2::info("DBus PowerMode Changed: {MODE}", "MODE", 1281 convertPowerModeToString(requestedMode)); 1282 1283 // Send mode change to OCC 1284 sendModeChange(); 1285 } 1286 else 1287 { 1288 // Not Allowed 1289 lg2::error( 1290 "PowerMode change not allowed. {MODE} is not in AllowedPowerModes", 1291 "MODE", convertPowerModeToString(requestedMode)); 1292 elog<NotAllowed>( 1293 xyz::openbmc_project::Common::NotAllowed::REASON( 1294 "PowerMode value not allowed")); 1295 } 1296 } 1297 else 1298 { 1299 // Value is not valid 1300 using InvalidArgument = 1301 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 1302 using Argument = xyz::openbmc_project::Common::InvalidArgument; 1303 lg2::error( 1304 "PowerMode not valid. {MODE} is not in AllowedPowerModes", 1305 "MODE", convertPowerModeToString(requestedMode)); 1306 elog<InvalidArgument>(Argument::ARGUMENT_NAME("PowerMode"), 1307 Argument::ARGUMENT_VALUE("INVALID MODE")); 1308 } 1309 } 1310 1311 // All elog<> calls will cause trap (so code will not make it here) 1312 1313 return Mode::powerMode(requestedMode); 1314 } 1315 1316 /* Set dbus property to SAFE mode(true) or clear(false) only if different 1317 */ 1318 void PowerMode::updateDbusSafeMode(const bool safeModeReq) 1319 { 1320 lg2::debug("PowerMode:updateDbusSafeMode: Update dbus state ({STATE})", 1321 "STATE", safeModeReq); 1322 1323 // Note; this function checks and only updates if different. 1324 Mode::safeMode(safeModeReq); 1325 } 1326 1327 // Get the supported power modes from DBus and return true if success 1328 bool PowerMode::getSupportedModes() 1329 { 1330 bool foundCustomerMode = false; 1331 using ModePropertyVariants = 1332 std::variant<bool, uint8_t, uint16_t, std::vector<std::string>>; 1333 std::map<std::string, ModePropertyVariants> powerModeProperties{}; 1334 1335 // Get all power mode properties from DBus 1336 try 1337 { 1338 auto& bus = utils::getBus(); 1339 std::string path = "/"; 1340 std::string service = 1341 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path); 1342 auto method = 1343 bus.new_method_call(service.c_str(), path.c_str(), 1344 "org.freedesktop.DBus.Properties", "GetAll"); 1345 method.append(PMODE_DEFAULT_INTERFACE); 1346 auto reply = bus.call(method); 1347 reply.read(powerModeProperties); 1348 } 1349 catch (const sdbusplus::exception_t& e) 1350 { 1351 lg2::error("Unable to read PowerModeProperties: {ERR}", "ERR", 1352 e.what()); 1353 return false; 1354 } 1355 1356 // Determine if system suports EcoModes 1357 auto ecoSupport = powerModeProperties.find("EcoModeSupport"); 1358 if (ecoSupport != powerModeProperties.end()) 1359 { 1360 ecoModeSupport = std::get<bool>(ecoSupport->second); 1361 lg2::info("getSupportedModes(): ecoModeSupport: {SUPPORT}", "SUPPORT", 1362 ecoModeSupport); 1363 } 1364 1365 // Determine what customer modes are supported 1366 using PMode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode; 1367 std::set<PMode::PowerMode> modesToAllow; 1368 auto custList = powerModeProperties.find("CustomerModes"); 1369 if (custList != powerModeProperties.end()) 1370 { 1371 auto modeList = std::get<std::vector<std::string>>(custList->second); 1372 for (auto mode : modeList) 1373 { 1374 // Ensure mode is valid 1375 const std::string fullModeString = 1376 PMODE_INTERFACE + ".PowerMode."s + mode; 1377 lg2::info("getSupportedModes(): {MODE}", "MODE", mode); 1378 SysPwrMode modeValue = 1379 powermode::convertStringToMode(fullModeString); 1380 if (VALID_POWER_MODE_SETTING(modeValue)) 1381 { 1382 if (!foundCustomerMode) 1383 { 1384 // Start with empty list 1385 customerModeList.clear(); 1386 foundCustomerMode = true; 1387 } 1388 // Add mode to list 1389 std::optional<PMode::PowerMode> cMode = 1390 PMode::convertStringToPowerMode(fullModeString); 1391 if (cMode) 1392 modesToAllow.insert(cMode.value()); 1393 customerModeList.insert(modeValue); 1394 } 1395 else 1396 { 1397 lg2::error( 1398 "getSupportedModes(): Ignoring unsupported customer mode {MODE}", 1399 "MODE", mode); 1400 } 1401 } 1402 } 1403 if (foundCustomerMode) 1404 { 1405 ModeInterface::allowedPowerModes(modesToAllow); 1406 } 1407 1408 // Determine what OEM modes are supported 1409 auto oemList = powerModeProperties.find("OemModes"); 1410 if (oemList != powerModeProperties.end()) 1411 { 1412 bool foundValidMode = false; 1413 auto OmodeList = std::get<std::vector<std::string>>(oemList->second); 1414 for (auto mode : OmodeList) 1415 { 1416 // Ensure mode is valid 1417 const std::string fullModeString = 1418 PMODE_INTERFACE + ".PowerMode."s + mode; 1419 SysPwrMode modeValue = 1420 powermode::convertStringToMode(fullModeString); 1421 if (VALID_POWER_MODE_SETTING(modeValue) || 1422 VALID_OEM_POWER_MODE_SETTING(modeValue)) 1423 { 1424 if (!foundValidMode) 1425 { 1426 // Start with empty list 1427 oemModeList.clear(); 1428 foundValidMode = true; 1429 } 1430 // Add mode to list 1431 oemModeList.insert(modeValue); 1432 } 1433 else 1434 { 1435 lg2::error( 1436 "getSupportedModes(): Ignoring unsupported OEM mode {MODE}", 1437 "MODE", mode); 1438 } 1439 } 1440 } 1441 1442 return foundCustomerMode; 1443 } 1444 1445 bool PowerMode::isValidMode(const SysPwrMode mode) 1446 { 1447 if (customerModeList.contains(mode) || oemModeList.contains(mode)) 1448 { 1449 return true; 1450 } 1451 return false; 1452 } 1453 1454 } // namespace powermode 1455 1456 } // namespace occ 1457 1458 } // namespace open_power 1459