oem_ibm: Implement timer for Surveillance Pings

This commit introduces a timer for surveillance pings sent by the
remote terminus to monitor the BMC. If a ping is not received
within 120 seconds, an informational error will be logged.

Signed-off-by: Sagar Srinivas <sagar.srinivas@ibm.com>
Change-Id: Ia52ed2461b2c2f8ea0102e60ed2a22c7691b2d2a
diff --git a/libpldmresponder/oem_handler.hpp b/libpldmresponder/oem_handler.hpp
index 2bcf36f..3b14ea8 100644
--- a/libpldmresponder/oem_handler.hpp
+++ b/libpldmresponder/oem_handler.hpp
@@ -113,6 +113,14 @@
     /** @brief Interface to the process setEventReceiver*/
     virtual void processSetEventReceiver() = 0;
 
+    /** @brief Interface to monitor the surveillance pings from remote terminus
+     *
+     * @param[in] tid - TID of the remote terminus
+     * @param[in] value - true or false, to indicate if the timer is
+     *                   running or not
+     * */
+    virtual void setSurvTimer(uint8_t tid, bool value) = 0;
+
     virtual ~Handler() = default;
 
   protected:
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 6c77159..2a19e66 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -360,7 +360,14 @@
         rc = PLDM_SUCCESS;
         if (oemPlatformHandler)
         {
-            oemPlatformHandler->resetWatchDogTimer();
+            if (oemPlatformHandler->watchDogRunning())
+            {
+                oemPlatformHandler->resetWatchDogTimer();
+            }
+            else
+            {
+                oemPlatformHandler->setSurvTimer(tid, true);
+            }
         }
     }
     else
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
index 4f3969c..8e207be 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
@@ -650,6 +650,43 @@
     this->setEventReceiver();
 }
 
+void pldm::responder::oem_ibm_platform::Handler::startStopTimer(bool value)
+{
+    if (value)
+    {
+        timer.restart(
+            std::chrono::seconds(HEARTBEAT_TIMEOUT + HEARTBEAT_TIMEOUT_DELTA));
+    }
+    else
+    {
+        timer.setEnabled(value);
+    }
+}
+
+void pldm::responder::oem_ibm_platform::Handler::setSurvTimer(uint8_t tid,
+                                                              bool value)
+{
+    if ((hostOff || hostTransitioningToOff || (tid != HYPERVISOR_TID)) &&
+        timer.isEnabled())
+    {
+        startStopTimer(false);
+        return;
+    }
+    if (value)
+    {
+        startStopTimer(value);
+    }
+    else if (timer.isEnabled())
+    {
+        info(
+            "Failed to stop surveillance timer while remote terminus status is ‘{HOST_TRANST_OFF}’ with Terminus ID ‘{TID}’ ",
+            "HOST_TRANST_OFF", hostTransitioningToOff, "TID", tid);
+        startStopTimer(value);
+        pldm::utils::reportError(
+            "xyz.openbmc_project.PLDM.Error.setSurvTimer.RecvSurveillancePingFail");
+    }
+}
+
 } // namespace oem_ibm_platform
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
index 9ad016f..319d1f7 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
@@ -10,6 +10,10 @@
 #include <libpldm/oem/ibm/state_set.h>
 #include <libpldm/platform.h>
 
+#include <sdbusplus/bus/match.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/utility/timer.hpp>
+
 typedef ibm_oem_pldm_state_set_firmware_update_state_values CodeUpdateState;
 
 namespace pldm
@@ -26,6 +30,10 @@
 constexpr uint32_t HOST_PDR_START_RANGE = 0x01000000;
 constexpr uint32_t HOST_PDR_END_RANGE = 0x01FFFFFF;
 
+const pldm::pdr::TerminusID HYPERVISOR_TID = 208;
+
+static constexpr uint8_t HEARTBEAT_TIMEOUT_DELTA = 10;
+
 enum SetEventReceiverCount
 {
     SET_EVENT_RECEIVER_SENT = 0x2,
@@ -42,7 +50,10 @@
         oem_platform::Handler(dBusIntf),
         codeUpdate(codeUpdate), platformHandler(nullptr), mctp_fd(mctp_fd),
         mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), event(event),
-        handler(handler)
+        handler(handler),
+        timer(event, std::bind(std::mem_fn(&Handler::setSurvTimer), this,
+                               HYPERVISOR_TID, false)),
+        hostTransitioningToOff(true)
     {
         codeUpdate->setVersions();
         setEventReceiverCnt = 0;
@@ -66,11 +77,19 @@
                     hostOff = true;
                     setEventReceiverCnt = 0;
                     disableWatchDogTimer();
+                    startStopTimer(false);
                 }
                 else if (propVal ==
                          "xyz.openbmc_project.State.Host.HostState.Running")
                 {
                     hostOff = false;
+                    hostTransitioningToOff = false;
+                }
+                else if (
+                    propVal ==
+                    "xyz.openbmc_project.State.Host.HostState.TransitioningToOff")
+                {
+                    hostTransitioningToOff = true;
                 }
             }
         });
@@ -217,6 +236,16 @@
         platformHandler->setEventReceiver();
     }
 
+    /** @brief Method to Enable/Disable timer to see if remote terminus sends
+     *  the surveillance ping and logs informational error if remote terminus
+     *  fails to send the surveillance pings
+     *
+     * @param[in] tid - TID of the remote terminus
+     * @param[in] value - true or false, to indicate if the timer is
+     *                    running or not
+     */
+    void setSurvTimer(uint8_t tid, bool value);
+
     ~Handler() = default;
 
     pldm::responder::CodeUpdate* codeUpdate; //!< pointer to CodeUpdate object
@@ -243,6 +272,13 @@
     sdeventplus::Event& event;
 
   private:
+    /** @brief Method to reset or stop the surveillance timer
+     *
+     * @param[in] value - true or false, to indicate if the timer
+     *                    should be reset or turned off
+     */
+    void startStopTimer(bool value);
+
     /** @brief D-Bus property changed signal match for CurrentPowerState*/
     std::unique_ptr<sdbusplus::bus::match_t> chassisOffMatch;
 
@@ -252,8 +288,13 @@
     /** @brief D-Bus property changed signal match */
     std::unique_ptr<sdbusplus::bus::match_t> hostOffMatch;
 
+    /** @brief Timer used for monitoring surveillance pings from host */
+    sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
+
     bool hostOff = true;
 
+    bool hostTransitioningToOff;
+
     int setEventReceiverCnt = 0;
 };