Create PowerMode object before status objects

Need to create the PowerMode object right away so that the Mode/IPS DBus
parameters are available to users as soon as service starts.
Previously it was only created when the OCC status objects were created.

Also populate the MinSoftPowerCapValue on DBus.

Change-Id: Ia0c7b5ba72a492b14bea7befe4f28c8b99e19ebd
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/occ_manager.cpp b/occ_manager.cpp
index c5038de..8a1469d 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -65,6 +65,13 @@
         createObjects(occ);
     }
 #else
+    if (!pmode)
+    {
+        // Create the power mode object
+        pmode = std::make_unique<powermode::PowerMode>(
+            *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event);
+    }
+
     if (!fs::exists(HOST_ON_FILE))
     {
         static bool statusObjCreated = false;
@@ -242,20 +249,6 @@
 {
     auto path = fs::path(OCC_CONTROL_ROOT) / occ;
 
-#ifdef POWER10
-    if (!pmode)
-    {
-        // Create the power mode object
-        pmode = std::make_unique<powermode::PowerMode>(
-            *this, powermode::PMODE_PATH, powermode::PIPS_PATH
-#ifdef POWER10
-            ,
-            event
-#endif
-        );
-    }
-#endif
-
     statusObjects.emplace_back(std::make_unique<Status>(
         event, path.c_str(), *this,
 #ifdef POWER10
diff --git a/powercap.cpp b/powercap.cpp
index 65d8998..9b102ab 100644
--- a/powercap.cpp
+++ b/powercap.cpp
@@ -20,6 +20,7 @@
 
 constexpr auto POWER_CAP_PROP = "PowerCap";
 constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
+constexpr auto POWER_CAP_SOFT_MIN = "MinSoftPowerCapValue";
 constexpr auto POWER_CAP_HARD_MIN = "MinPowerCapValue";
 constexpr auto POWER_CAP_MAX = "MaxPowerCapValue";
 
@@ -30,11 +31,31 @@
 {
     // Build the hwmon string to write the power cap bounds
     fs::path minName = getPcapFilename(std::regex{"power\\d+_cap_min$"});
+    fs::path softMinName =
+        getPcapFilename(std::regex{"power\\d+_cap_min_soft$"});
     fs::path maxName = getPcapFilename(std::regex{"power\\d+_cap_max$"});
 
     // Read the power cap bounds from sysfs files
     uint64_t cap;
-    uint32_t capHardMin = 0, capMax = INT_MAX;
+    uint32_t capSoftMin = 0, capHardMin = 0, capMax = INT_MAX;
+
+    std::ifstream softMinFile(softMinName, std::ios::in);
+    if (softMinFile)
+    {
+        softMinFile >> cap;
+        softMinFile.close();
+        // Convert to Input Power in Watts (round up)
+        capSoftMin = ((cap / (PS_DERATING_FACTOR / 100.0) / 1000000) + 0.9);
+    }
+    else
+    {
+        log<level::ERR>(
+            fmt::format(
+                "updatePcapBounds: unable to find pcap_min_soft file: {} (errno={})",
+                pcapBasePathname.c_str(), errno)
+                .c_str());
+    }
+
     std::ifstream minFile(minName, std::ios::in);
     if (minFile)
     {
@@ -51,6 +72,7 @@
                 pcapBasePathname.c_str(), errno)
                 .c_str());
     }
+
     std::ifstream maxFile(maxName, std::ios::in);
     if (maxFile)
     {
@@ -69,7 +91,7 @@
     }
 
     // Save the bounds to dbus
-    updateDbusPcap(capHardMin, capMax);
+    updateDbusPcap(capSoftMin, capHardMin, capMax);
 
     // Validate dbus and hwmon user caps match
     const uint32_t dbusUserCap = getPcap();
@@ -312,12 +334,27 @@
 }
 
 // Update the Power Cap bounds on DBus
-bool PowerCap::updateDbusPcap(uint32_t hardMin, uint32_t max)
+bool PowerCap::updateDbusPcap(uint32_t softMin, uint32_t hardMin, uint32_t max)
 {
     bool complete = true;
 
     try
     {
+        utils::setProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_SOFT_MIN,
+                           softMin);
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        log<level::ERR>(
+            fmt::format(
+                "updateDbusPcap: Failed to set SOFT PCAP to {}W due to {}",
+                softMin, e.what())
+                .c_str());
+        complete = false;
+    }
+
+    try
+    {
         utils::setProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_HARD_MIN,
                            hardMin);
     }
diff --git a/powercap.hpp b/powercap.hpp
index 6d611db..edc68c6 100644
--- a/powercap.hpp
+++ b/powercap.hpp
@@ -122,12 +122,13 @@
 
     /** @brief Update the power cap bounds on DBus
      *
+     * @param[in]  softMin - soft minimum power cap in Watts
      * @param[in]  hardMin - hard minimum power cap in Watts
      * @param[in]  pcapMax - maximum power cap in Watts
      *
      * @return true if all parms were written successfully
      */
-    bool updateDbusPcap(uint32_t hardMin, uint32_t pcapMax);
+    bool updateDbusPcap(uint32_t softMin, uint32_t hardMin, uint32_t pcapMax);
 };
 
 } // namespace powercap