BMC:  Fan control for Idle Power saver

Read IPS active from sysfs and push onto dBus IPS properties
Tested: enable/disable IPS on WEB, occ instrospect ips
Signed-off-by: Sheldon Bailey <baileysh@us.ibm.com>
Change-Id: I12935a4c9f82bf004b1311e477f73ed8b1401a91
diff --git a/powermode.hpp b/powermode.hpp
index d15eea7..dbd68eb 100644
--- a/powermode.hpp
+++ b/powermode.hpp
@@ -39,6 +39,7 @@
 constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
 constexpr auto PIPS_INTERFACE =
     "xyz.openbmc_project.Control.Power.IdlePowerSaver";
+constexpr auto IPS_ACTIVE_PROP = "Active";
 constexpr auto IPS_ENABLED_PROP = "Enabled";
 constexpr auto IPS_ENTER_UTIL = "EnterUtilizationPercent";
 constexpr auto IPS_ENTER_TIME = "EnterDwellTime";
@@ -233,7 +234,12 @@
      * @param[in] ipsPath - Idle Power Saver dbus path
      */
     explicit PowerMode(const Manager& managerRef, const char* modePath,
-                       const char* ipsPath) :
+                       const char* ipsPath
+#ifdef POWER10
+                       ,
+                       EventPtr& event
+#endif
+                       ) :
         ModeInterface(utils::getBus(), modePath, false),
         IpsInterface(utils::getBus(), ipsPath, false), manager(managerRef),
         pmodeMatch(utils::getBus(),
@@ -250,6 +256,10 @@
                 "/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE),
             [this](auto& msg) { this->defaultsReady(msg); }),
         masterOccSet(false), masterActive(false)
+#ifdef POWER10
+        ,
+        event(event)
+#endif
     {
         // restore Power Mode to DBus
         SysPwrMode currentMode;
@@ -309,6 +319,18 @@
         masterActive = isActive;
     };
 
+#ifdef POWER10
+    /** @brief Starts to monitor for IPS active state change conditions
+     *
+     *  @param[in] poll - Indicates whether or not the IPS state file should
+     *                    actually be read for changes.
+     */
+    void addIpsWatch(bool poll = true);
+
+    /** @brief Removes IPS active watch */
+    void removeIpsWatch();
+#endif
+
   private:
     /** @brief OCC manager object */
     const Manager& manager;
@@ -339,6 +361,19 @@
     /** @brief True when the master OCC is active */
     bool masterActive;
 
+#ifdef POWER10
+    /** @brief IPS status data filename to read */
+    const fs::path ipsStatusFile = std::filesystem::path{OCC_HWMON_PATH} /
+                                   std::filesystem::path{OCC_MASTER_NAME} /
+                                   "occ_ips_status";
+
+    /** @brief Current state of error watching */
+    bool watching = false;
+
+    /** @brief register for the callback from the POLL IPS changed event */
+    void registerIpsStatusCallBack();
+#endif
+
     /** @brief Callback for pmode setting changes
      *
      * Process change and inform OCC
@@ -435,6 +470,34 @@
      * @return true if restore was successful
      */
     bool useDefaultIPSParms();
+
+#ifdef POWER10
+    /** @brief callback for the POLL IPS changed event
+     *
+     *  @param[in] es       - Populated event source
+     *  @param[in] fd       - Associated File descriptor
+     *  @param[in] revents  - Type of event
+     *  @param[in] userData - User data that was passed during registration
+     */
+    static int ipsStatusCallBack(sd_event_source* es, int fd, uint32_t revents,
+                                 void* userData);
+
+    /** @brief Opens the IPS file and populates fd */
+    bool openIpsFile();
+
+    /** @brief sd_event wrapped in unique_ptr */
+    EventPtr& event;
+
+    /** @brief event source wrapped in unique_ptr */
+    EventSourcePtr eventSource;
+
+    /** @brief When the ips status event is received, analyzes it */
+    virtual void analyzeIpsEvent();
+
+  protected:
+    /** @brief File descriptor to watch for errors */
+    int fd = -1;
+#endif
 };
 
 } // namespace powermode