Read default power mode & IPS parameters from DBus

If the power mode or idle power saver parameters have never been set,
they will be read from a set of default parameters that are on DBus.
This allows individual systems to have different default settings.
Mode/IPS parameters moved from Settings to OCC.Control

Code verified on Everest hardware with multiple scenarios including
host reboots, BMC reboots, OCC resets.

Change-Id: Id02613455db7f382791ff37c7dc420dbea1e0906
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/powermode.cpp b/powermode.cpp
index 9b9f3cb..fd8679d 100644
--- a/powermode.cpp
+++ b/powermode.cpp
@@ -18,18 +18,38 @@
 {
 
 using namespace phosphor::logging;
+using namespace std::literals::string_literals;
+
 using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode;
 
 // Set the Master OCC
-void PowerMode::setMasterOcc(const std::string& occPath)
+void PowerMode::setMasterOcc(const std::string& masterOccPath)
 {
-    path = occPath;
+    if (masterOccSet)
+    {
+        if (masterOccPath != path)
+        {
+            log<level::ERR>(
+                fmt::format(
+                    "PowerMode::setMasterOcc: Master changed (was OCC{}, {})",
+                    occInstance, masterOccPath)
+                    .c_str());
+            if (occCmd)
+            {
+                occCmd.reset();
+            }
+        }
+    }
+    path = masterOccPath;
     occInstance = path.back() - '0';
     log<level::DEBUG>(fmt::format("PowerMode::setMasterOcc(OCC{}, {})",
                                   occInstance, path.c_str())
                           .c_str());
-    occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance,
-                                                           path.c_str());
+    if (!occCmd)
+    {
+        occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance,
+                                                               path.c_str());
+    }
     masterOccSet = true;
 };
 
@@ -48,12 +68,11 @@
         SysPwrMode newMode = convertStringToMode(propVal);
         if (newMode != SysPwrMode::NO_CHANGE)
         {
-            // DBus mode changed, get rid of any OEM mode if set
-            persistedData.purge();
+            // Update persisted data with new mode
+            persistedData.updateMode(newMode, 0);
 
             log<level::INFO>(
-                fmt::format("Power Mode Change Requested: {}", propVal)
-                    .c_str());
+                fmt::format("DBus Power Mode Changed: {}", propVal).c_str());
 
             // Send mode change to OCC
             sendModeChange();
@@ -62,7 +81,7 @@
 }
 
 // Called from OCC PassThrough interface (via CE login / BMC command line)
-bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t modeData)
+bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t oemModeData)
 {
     if (updateDbusMode(newMode) == false)
     {
@@ -70,19 +89,14 @@
         return false;
     }
 
-    // If new mode is valid customer mode, the DBus update will trigger the mode
-    // change request to OCC.  For OEM modes, the request will be sent here.
-    if (VALID_OEM_POWER_MODE_SETTING(newMode))
-    {
-        // Save OEM mode
-        persistedData.writeModeFile(newMode, modeData);
+    // Save mode
+    persistedData.updateMode(newMode, oemModeData);
 
-        // Send mode change to OCC
-        if (sendModeChange() != CmdStatus::SUCCESS)
-        {
-            // Mode change failed
-            return false;
-        }
+    // Send mode change to OCC
+    if (sendModeChange() != CmdStatus::SUCCESS)
+    {
+        // Mode change failed
+        return false;
     }
 
     return true;
@@ -125,7 +139,6 @@
 // Check if Hypervisor target is PowerVM
 bool isPowerVM()
 {
-    using namespace open_power::occ::powermode;
     namespace Hyper = sdbusplus::com::ibm::Host::server;
     constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
     constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
@@ -156,44 +169,81 @@
     return powerVmTarget;
 }
 
-// Get the requested power mode from DBus
-SysPwrMode PowerMode::getDbusMode()
+// Initialize persistent data and return true if successful
+bool PowerMode::initPersistentData()
 {
-    using namespace open_power::occ::powermode;
-    SysPwrMode currentMode;
-
-    // This will throw exception on failure
-    auto& bus = utils::getBus();
-    auto service = utils::getService(PMODE_PATH, PMODE_INTERFACE);
-    auto method = bus.new_method_call(service.c_str(), PMODE_PATH,
-                                      "org.freedesktop.DBus.Properties", "Get");
-    method.append(PMODE_INTERFACE, POWER_MODE_PROP);
-    auto reply = bus.call(method);
-
-    std::variant<std::string> stateEntryValue;
-    reply.read(stateEntryValue);
-    auto propVal = std::get<std::string>(stateEntryValue);
-
-    currentMode = powermode::convertStringToMode(propVal);
-    if (!VALID_POWER_MODE_SETTING(currentMode))
+    if (!persistedData.modeAvailable())
     {
-        log<level::ERR>(
-            fmt::format(
-                "PowerMode::getDbusMode Invalid power mode found on DBus: {}",
-                currentMode)
+        // Read the default mode
+        SysPwrMode currentMode;
+        if (!getDefaultMode(currentMode))
+        {
+            // Unable to read defaults
+            return false;
+        }
+        log<level::INFO>(
+            fmt::format("PowerMode::initPersistentData: Using default mode: {}",
+                        currentMode)
                 .c_str());
-        currentMode = SysPwrMode::NO_CHANGE;
+
+        // Save default mode as current mode
+        persistedData.updateMode(currentMode, 0);
+
+        // Write default mode to DBus
+        updateDbusMode(currentMode);
     }
 
-    return currentMode;
+    if (!persistedData.ipsAvailable())
+    {
+        // Read the default IPS parameters
+        bool ipsEnabled;
+        uint8_t enterUtil, exitUtil;
+        uint16_t enterTime, exitTime;
+        if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil,
+                                exitTime))
+        {
+            // Unable to read defaults
+            return false;
+        }
+        log<level::INFO>(
+            fmt::format(
+                "PowerMode::initPersistentData: Using default IPS parms: Enabled: {}, EnterUtil: {}%, EnterTime: {}s, ExitUtil: {}%, ExitTime: {}s",
+                ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
+                .c_str());
+
+        // Save IPS
+        persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
+                                exitTime);
+
+        // Write default IPS data to DBus
+        updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
+    }
+    return true;
+}
+
+// Get the requested power mode and return true if successful
+bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData)
+{
+    currentMode = SysPwrMode::NO_CHANGE;
+    oemModeData = 0;
+
+    if (!persistedData.getMode(currentMode, oemModeData))
+    {
+        // Persistent data not initialized, read defaults and update DBus
+        if (!initPersistentData())
+        {
+            // Unable to read defaults from entity manager yet
+            return false;
+        }
+        return persistedData.getMode(currentMode, oemModeData);
+    }
+
+    return true;
 }
 
 // Set the power mode on DBus
 bool PowerMode::updateDbusMode(const SysPwrMode newMode)
 {
-    using namespace open_power::occ::powermode;
-    using namespace std::literals::string_literals;
-
     if (!VALID_POWER_MODE_SETTING(newMode) &&
         !VALID_OEM_POWER_MODE_SETTING(newMode))
     {
@@ -205,25 +255,25 @@
         return false;
     }
 
-    // Mode::PowerMode dBusMode;
-    std::string dBusMode;
+    // Convert mode for DBus
+    ModeInterface::PowerMode dBusMode;
     switch (newMode)
     {
         case SysPwrMode::STATIC:
-            dBusMode = PMODE_INTERFACE + ".PowerMode.Static"s;
+            dBusMode = Mode::PowerMode::Static;
             break;
         case SysPwrMode::POWER_SAVING:
-            dBusMode = PMODE_INTERFACE + ".PowerMode.PowerSaving"s;
+            dBusMode = Mode::PowerMode::PowerSaving;
             break;
         case SysPwrMode::MAX_PERF:
-            dBusMode = PMODE_INTERFACE + ".PowerMode.MaximumPerformance"s;
+            dBusMode = Mode::PowerMode::MaximumPerformance;
             break;
         default:
-            dBusMode = PMODE_INTERFACE + ".PowerMode.OEM"s;
+            dBusMode = Mode::PowerMode::OEM;
     }
 
-    utils::setProperty(PMODE_PATH, PMODE_INTERFACE, POWER_MODE_PROP,
-                       std::move(dBusMode));
+    // true = skip update signal
+    ModeInterface::setPropertyByName(POWER_MODE_PROP, dBusMode, true);
 
     return true;
 }
@@ -248,14 +298,9 @@
         return CmdStatus::SUCCESS;
     }
 
-    // Use OEM power mode if it was set
-    SysPwrMode newMode = SysPwrMode::NO_CHANGE;
-    uint16_t modeData = 0;
-    if (persistedData.getOemMode(newMode, modeData) == false)
-    {
-        // Read customer power mode from Dbus
-        newMode = getDbusMode();
-    }
+    SysPwrMode newMode;
+    uint16_t oemModeData = 0;
+    getMode(newMode, oemModeData);
 
     if (VALID_POWER_MODE_SETTING(newMode) ||
         VALID_OEM_POWER_MODE_SETTING(newMode))
@@ -268,13 +313,13 @@
         cmd.push_back(0x30); // Data (Version)
         cmd.push_back(uint8_t(OccState::NO_CHANGE));
         cmd.push_back(uint8_t(newMode));
-        cmd.push_back(modeData >> 8);   // Mode Data (Freq Point)
-        cmd.push_back(modeData & 0xFF); //
-        cmd.push_back(0x00);            // reserved
+        cmd.push_back(oemModeData >> 8);   // Mode Data (Freq Point)
+        cmd.push_back(oemModeData & 0xFF); //
+        cmd.push_back(0x00);               // reserved
         log<level::INFO>(
             fmt::format(
                 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)",
-                newMode, modeData, occInstance, cmd.size())
+                newMode, oemModeData, occInstance, cmd.size())
                 .c_str());
         status = occCmd->send(cmd, rsp);
         if (status == CmdStatus::SUCCESS)
@@ -340,10 +385,17 @@
         ipsProperties{};
     msg.read(interface, ipsProperties);
 
+    // Read persisted values
+    bool ipsEnabled;
+    uint8_t enterUtil, exitUtil;
+    uint16_t enterTime, exitTime;
+    getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
+
+    // Check for any changed data
     auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
     if (ipsEntry != ipsProperties.end())
     {
-        const auto ipsEnabled = std::get<bool>(ipsEntry->second);
+        ipsEnabled = std::get<bool>(ipsEntry->second);
         log<level::INFO>(
             fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
                 .c_str());
@@ -352,7 +404,7 @@
     ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
     if (ipsEntry != ipsProperties.end())
     {
-        const auto enterUtil = std::get<uint8_t>(ipsEntry->second);
+        enterUtil = std::get<uint8_t>(ipsEntry->second);
         log<level::INFO>(
             fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
                 .c_str());
@@ -362,7 +414,7 @@
     if (ipsEntry != ipsProperties.end())
     {
         std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
-        const auto enterTime =
+        enterTime =
             std::chrono::duration_cast<std::chrono::seconds>(ms).count();
         log<level::INFO>(
             fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
@@ -372,7 +424,7 @@
     ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
     if (ipsEntry != ipsProperties.end())
     {
-        const auto exitUtil = std::get<uint8_t>(ipsEntry->second);
+        exitUtil = std::get<uint8_t>(ipsEntry->second);
         log<level::INFO>(
             fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
                 .c_str());
@@ -382,8 +434,7 @@
     if (ipsEntry != ipsProperties.end())
     {
         std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
-        const auto exitTime =
-            std::chrono::duration_cast<std::chrono::seconds>(ms).count();
+        exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
         log<level::INFO>(
             fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
                 .c_str());
@@ -392,118 +443,43 @@
 
     if (parmsChanged)
     {
-        // Trigger mode change to OCC
+        // Update persistant data with new DBus values
+        persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
+                                exitTime);
+
+        // Trigger IPS data to get sent to the OCC
         sendIpsData();
     }
 
     return;
 }
 
-/** @brief Get the Idle Power Saver properties
- * @return true if IPS is enabled
+/** @brief Get the Idle Power Saver properties from persisted data
+ * @return true if IPS parameters were read
  */
-bool PowerMode::getIPSParms(uint8_t& enterUtil, uint16_t& enterTime,
-                            uint8_t& exitUtil, uint16_t& exitTime)
+bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
+                            uint16_t& enterTime, uint8_t& exitUtil,
+                            uint16_t& exitTime)
 {
-    using namespace open_power::occ::powermode;
     // Defaults:
-    bool ipsEnabled = false; // Disabled
-    enterUtil = 8;           // Enter Utilization (8%)
-    enterTime = 240;         // Enter Delay Time (240s)
-    exitUtil = 12;           // Exit Utilization (12%)
-    exitTime = 10;           // Exit Delay Time (10s)
+    ipsEnabled = true; // Enabled
+    enterUtil = 8;     // Enter Utilization (8%)
+    enterTime = 240;   // Enter Delay Time (240s)
+    exitUtil = 12;     // Exit Utilization (12%)
+    exitTime = 10;     // Exit Delay Time (10s)
 
-    std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
-        ipsProperties{};
+    if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
+                              exitTime))
+    {
+        // Persistent data not initialized, read defaults and update DBus
+        if (!initPersistentData())
+        {
+            // Unable to read defaults from entity manager yet
+            return false;
+        }
 
-    // Get all IPS properties from DBus
-    try
-    {
-        auto& bus = utils::getBus();
-        auto service = utils::getService(PIPS_PATH, PIPS_INTERFACE);
-        auto method =
-            bus.new_method_call(service.c_str(), PIPS_PATH,
-                                "org.freedesktop.DBus.Properties", "GetAll");
-        method.append(PIPS_INTERFACE);
-        auto reply = bus.call(method);
-        reply.read(ipsProperties);
-    }
-    catch (const sdbusplus::exception::exception& e)
-    {
-        log<level::ERR>(
-            fmt::format(
-                "Unable to read Idle Power Saver parameters so it will be disabled: {}",
-                e.what())
-                .c_str());
-        return ipsEnabled;
-    }
-
-    auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
-    if (ipsEntry != ipsProperties.end())
-    {
-        ipsEnabled = std::get<bool>(ipsEntry->second);
-    }
-    else
-    {
-        log<level::ERR>(
-            fmt::format("PowerMode::getIPSParms could not find property: {}",
-                        IPS_ENABLED_PROP)
-                .c_str());
-    }
-
-    ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
-    if (ipsEntry != ipsProperties.end())
-    {
-        enterUtil = std::get<uint8_t>(ipsEntry->second);
-    }
-    else
-    {
-        log<level::ERR>(
-            fmt::format("PowerMode::getIPSParms could not find property: {}",
-                        IPS_ENTER_UTIL)
-                .c_str());
-    }
-
-    ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
-    if (ipsEntry != ipsProperties.end())
-    {
-        std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
-        enterTime =
-            std::chrono::duration_cast<std::chrono::seconds>(ms).count();
-    }
-    else
-    {
-        log<level::ERR>(
-            fmt::format("PowerMode::getIPSParms could not find property: {}",
-                        IPS_ENTER_TIME)
-                .c_str());
-    }
-
-    ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
-    if (ipsEntry != ipsProperties.end())
-    {
-        exitUtil = std::get<uint8_t>(ipsEntry->second);
-    }
-    else
-    {
-        log<level::ERR>(
-            fmt::format("PowerMode::getIPSParms could not find property: {}",
-                        IPS_EXIT_UTIL)
-                .c_str());
-    }
-
-    ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
-    if (ipsEntry != ipsProperties.end())
-    {
-        std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
-        exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
-    }
-    else
-    {
-        log<level::ERR>(
-            fmt::format("PowerMode::getIPSParms could not find property: {}",
-                        IPS_EXIT_TIME)
-                .c_str());
+        persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
+                             exitTime);
     }
 
     if (enterUtil > exitUtil)
@@ -516,14 +492,30 @@
         enterUtil = exitUtil;
     }
 
-    return ipsEnabled;
+    return true;
+}
+
+// Set the Idle Power Saver data on DBus
+bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil,
+                              const uint16_t enterTime, const uint8_t exitUtil,
+                              const uint16_t exitTime)
+{
+    // true = skip update signal
+    IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true);
+    IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
+    // Convert time from seconds to ms
+    uint64_t msTime = enterTime * 1000;
+    IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true);
+    IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
+    msTime = exitTime * 1000;
+    IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true);
+
+    return true;
 }
 
 // Send Idle Power Saver config data to the master OCC
 CmdStatus PowerMode::sendIpsData()
 {
-    CmdStatus status;
-
     if (!masterActive || !masterOccSet)
     {
         // Nothing to do
@@ -538,10 +530,10 @@
         return CmdStatus::SUCCESS;
     }
 
+    bool ipsEnabled;
     uint8_t enterUtil, exitUtil;
     uint16_t enterTime, exitTime;
-    const bool ipsEnabled =
-        getIPSParms(enterUtil, enterTime, exitUtil, exitTime);
+    getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
 
     log<level::INFO>(
         fmt::format(
@@ -567,7 +559,7 @@
                                  "command to OCC{} ({} bytes)",
                                  occInstance, cmd.size())
                          .c_str());
-    status = occCmd->send(cmd, rsp);
+    CmdStatus status = occCmd->send(cmd, rsp);
     if (status == CmdStatus::SUCCESS)
     {
         if (rsp.size() == 5)
@@ -608,20 +600,33 @@
     return status;
 }
 
-inline void OccPersistData::print()
+void OccPersistData::print()
 {
-    log<level::DEBUG>(
-        fmt::format(
-            "OccPersistData: OEM Mode: 0x{:02X}, OEM Mode Freq: {} (0x{:04X})",
-            oemData.oemMode, oemData.oemModeFreq, oemData.oemModeFreq)
-            .c_str());
+    if (modeData.modeInitialized)
+    {
+        log<level::INFO>(
+            fmt::format(
+                "OccPersistData: Mode: 0x{:02X}, OEM Mode Data: {} (0x{:04X})",
+                modeData.mode, modeData.oemModeData, modeData.oemModeData)
+                .c_str());
+    }
+    if (modeData.ipsInitialized)
+    {
+        log<level::INFO>(
+            fmt::format(
+                "OccPersistData: IPS enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
+                modeData.ipsEnabled, modeData.ipsEnterUtil,
+                modeData.ipsEnterTime, modeData.ipsExitUtil,
+                modeData.ipsExitTime)
+                .c_str());
+    }
 }
 
 // Saves the OEM mode data in the filesystem using cereal.
 void OccPersistData::save()
 {
     std::filesystem::path opath =
-        std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
+        std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
 
     if (!std::filesystem::exists(opath.parent_path()))
     {
@@ -629,15 +634,16 @@
     }
 
     log<level::DEBUG>(
-        fmt::format("OccPersistData::save: Writing OEM persisted data to {}",
-                    opath.c_str())
+        fmt::format(
+            "OccPersistData::save: Writing Power Mode persisted data to {}",
+            opath.c_str())
             .c_str());
     print();
 
     std::ofstream stream{opath.c_str()};
     cereal::JSONOutputArchive oarchive{stream};
 
-    oarchive(oemData);
+    oarchive(modeData);
 }
 
 // Loads the OEM mode data in the filesystem using cereal.
@@ -645,24 +651,25 @@
 {
 
     std::filesystem::path ipath =
-        std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
+        std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
 
     if (!std::filesystem::exists(ipath))
     {
+        modeData.modeInitialized = false;
+        modeData.ipsInitialized = false;
         return;
     }
 
     log<level::DEBUG>(
-        fmt::format("OccPersistData::load: Reading OEM persisted data from {}",
-                    ipath.c_str())
+        fmt::format(
+            "OccPersistData::load: Reading Power Mode persisted data from {}",
+            ipath.c_str())
             .c_str());
     try
     {
         std::ifstream stream{ipath.c_str()};
         cereal::JSONInputArchive iarchive(stream);
-        iarchive(oemData);
-
-        oemSet = true;
+        iarchive(modeData);
     }
     catch (const std::exception& e)
     {
@@ -671,28 +678,185 @@
             fmt::format("OccPersistData::load: failed to read {}, errno={}",
                         ipath.c_str(), error)
                 .c_str());
+        modeData.modeInitialized = false;
+        modeData.ipsInitialized = false;
     }
 
     print();
 }
 
-void OccPersistData::purge()
+// Called when PowerModeProperties defaults are available on DBus
+void PowerMode::defaultsReady(sdbusplus::message::message& msg)
 {
-    std::filesystem::path opath =
-        std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
+    std::map<std::string, std::variant<std::string>> properties{};
+    std::string interface;
+    msg.read(interface, properties);
 
-    if (!std::filesystem::exists(opath))
+    // If persistent data exists, then don't need to read defaults
+    if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable()))
     {
-        return;
+        log<level::INFO>(
+            fmt::format(
+                "Default PowerModeProperties are now available (persistent modeAvail={}, ipsAvail={})",
+                persistedData.modeAvailable() ? 'y' : 'n',
+                persistedData.modeAvailable() ? 'y' : 'n')
+                .c_str());
+
+        // Read default power mode defaults and update DBus
+        initPersistentData();
+    }
+}
+
+// Get the default power mode from DBus and return true if success
+bool PowerMode::getDefaultMode(SysPwrMode& defaultMode)
+{
+    try
+    {
+        auto& bus = utils::getBus();
+        std::string path = "/";
+        std::string service =
+            utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
+        auto method =
+            bus.new_method_call(service.c_str(), path.c_str(),
+                                "org.freedesktop.DBus.Properties", "Get");
+        method.append(PMODE_DEFAULT_INTERFACE, "PowerMode");
+        auto reply = bus.call(method);
+
+        std::variant<std::string> stateEntryValue;
+        reply.read(stateEntryValue);
+        auto propVal = std::get<std::string>(stateEntryValue);
+
+        const std::string fullModeString =
+            PMODE_INTERFACE + ".PowerMode."s + propVal;
+        defaultMode = powermode::convertStringToMode(fullModeString);
+        if (!VALID_POWER_MODE_SETTING(defaultMode))
+        {
+            log<level::ERR>(
+                fmt::format(
+                    "PowerMode::getDefaultMode: Invalid default power mode found: {}",
+                    defaultMode)
+                    .c_str());
+            // If default was read but not valid, use Max Performance
+            defaultMode = SysPwrMode::MAX_PERF;
+            return true;
+        }
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        log<level::ERR>(
+            fmt::format("Unable to read Default Power Mode: {}", e.what())
+                .c_str());
+        return false;
     }
 
-    print();
-    log<level::DEBUG>("OccPersistData::purge() Removing OEM data");
+    return true;
+}
 
-    oemSet = false;
-    oemData.oemMode = SysPwrMode::NO_CHANGE;
-    oemData.oemModeFreq = 0x0000;
-    remove(opath.c_str());
+/* Get the default Idle Power Saver properties and return true if successful */
+bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
+                                   uint16_t& enterTime, uint8_t& exitUtil,
+                                   uint16_t& exitTime)
+{
+    // Defaults:
+    ipsEnabled = true; // Enabled
+    enterUtil = 8;     // Enter Utilization (8%)
+    enterTime = 240;   // Enter Delay Time (240s)
+    exitUtil = 12;     // Exit Utilization (12%)
+    exitTime = 10;     // Exit Delay Time (10s)
+
+    std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>>
+        ipsProperties{};
+
+    // Get all IPS properties from DBus
+    try
+    {
+        auto& bus = utils::getBus();
+        std::string path = "/";
+        std::string service =
+            utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
+        auto method =
+            bus.new_method_call(service.c_str(), path.c_str(),
+                                "org.freedesktop.DBus.Properties", "GetAll");
+        method.append(PMODE_DEFAULT_INTERFACE);
+        auto reply = bus.call(method);
+        reply.read(ipsProperties);
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        log<level::ERR>(
+            fmt::format(
+                "Unable to read Default Idle Power Saver parameters so it will be disabled: {}",
+                e.what())
+                .c_str());
+        return false;
+    }
+
+    auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled");
+    if (ipsEntry != ipsProperties.end())
+    {
+        ipsEnabled = std::get<bool>(ipsEntry->second);
+    }
+    else
+    {
+        log<level::ERR>(
+            "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled");
+    }
+
+    ipsEntry = ipsProperties.find("EnterUtilizationPercent");
+    if (ipsEntry != ipsProperties.end())
+    {
+        enterUtil = std::get<uint64_t>(ipsEntry->second);
+    }
+    else
+    {
+        log<level::ERR>(
+            "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent");
+    }
+
+    ipsEntry = ipsProperties.find("EnterUtilizationDwellTime");
+    if (ipsEntry != ipsProperties.end())
+    {
+        enterTime = std::get<uint64_t>(ipsEntry->second);
+    }
+    else
+    {
+        log<level::ERR>(
+            "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime");
+    }
+
+    ipsEntry = ipsProperties.find("ExitUtilizationPercent");
+    if (ipsEntry != ipsProperties.end())
+    {
+        exitUtil = std::get<uint64_t>(ipsEntry->second);
+    }
+    else
+    {
+        log<level::ERR>(
+            "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent");
+    }
+
+    ipsEntry = ipsProperties.find("ExitUtilizationDwellTime");
+    if (ipsEntry != ipsProperties.end())
+    {
+        exitTime = std::get<uint64_t>(ipsEntry->second);
+    }
+    else
+    {
+        log<level::ERR>(
+            "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime");
+    }
+
+    if (enterUtil > exitUtil)
+    {
+        log<level::ERR>(
+            fmt::format(
+                "ERROR: Default Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
+                enterUtil, exitUtil)
+                .c_str());
+        enterUtil = exitUtil;
+    }
+
+    return true;
 }
 
 } // namespace powermode