Add ERR0 timeout monitoring and logging

This adds ERR0 timeout monitoring to the host error monitor.  When
the ERR0 signal is asserted for more than 90 seconds, the BMC will
log which CPU asserted the ERR0 signal.

Tested:
Manually triggered an ERR0 timeout and confirmed that the event is
logged correctly.

Change-Id: I1d2811b5d020a554870e687b0926c3f9211147d0
Signed-off-by: Jason M. Bills <jason.m.bills@intel.com>
diff --git a/src/host_error_monitor.cpp b/src/host_error_monitor.cpp
index 0ef43be..408acc9 100644
--- a/src/host_error_monitor.cpp
+++ b/src/host_error_monitor.cpp
@@ -38,6 +38,8 @@
 // Timers
 // Timer for CATERR asserted
 static boost::asio::steady_timer caterrAssertTimer(io);
+// Timer for ERR0 asserted
+static boost::asio::steady_timer err0AssertTimer(io);
 // Timer for ERR2 asserted
 static boost::asio::steady_timer err2AssertTimer(io);
 // Timer for SMI asserted
@@ -46,6 +48,8 @@
 // GPIO Lines and Event Descriptors
 static gpiod::line caterrLine;
 static boost::asio::posix::stream_descriptor caterrEvent(io);
+static gpiod::line err0Line;
+static boost::asio::posix::stream_descriptor err0Event(io);
 static gpiod::line err2Line;
 static boost::asio::posix::stream_descriptor err2Event(io);
 static gpiod::line smiLine;
@@ -173,6 +177,7 @@
             if (hostOff)
             {
                 caterrAssertTimer.cancel();
+                err0AssertTimer.cancel();
                 err2AssertTimer.cancel();
                 smiAssertTimer.cancel();
             }
@@ -733,6 +738,42 @@
     });
 }
 
+static void err0AssertHandler()
+{
+    // Handle the standard ERR0 detection and logging
+    const static constexpr int err0 = 0;
+    errXAssertHandler(err0, err0AssertTimer);
+}
+
+static void err0Handler()
+{
+    if (!hostOff)
+    {
+        gpiod::line_event gpioLineEvent = err0Line.event_read();
+
+        bool err0 = gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
+        if (err0)
+        {
+            err0AssertHandler();
+        }
+        else
+        {
+            err0AssertTimer.cancel();
+        }
+    }
+    err0Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
+                         [](const boost::system::error_code ec) {
+                             if (ec)
+                             {
+                                 std::cerr
+                                     << "err0 handler error: " << ec.message()
+                                     << "\n";
+                                 return;
+                             }
+                             err0Handler();
+                         });
+}
+
 static void err2AssertHandler()
 {
     // Handle the standard ERR2 detection and logging
@@ -879,6 +920,12 @@
         caterrAssertHandler();
     }
 
+    // Handle CPU_ERR0 if it's asserted now
+    if (err0Line.get_value() == 0)
+    {
+        err0AssertHandler();
+    }
+
     // Handle CPU_ERR2 if it's asserted now
     if (err2Line.get_value() == 0)
     {
@@ -926,6 +973,14 @@
         return -1;
     }
 
+    // Request CPU_ERR0 GPIO events
+    if (!host_error_monitor::requestGPIOEvents(
+            "CPU_ERR0", host_error_monitor::err0Handler,
+            host_error_monitor::err0Line, host_error_monitor::err0Event))
+    {
+        return -1;
+    }
+
     // Request CPU_ERR2 GPIO events
     if (!host_error_monitor::requestGPIOEvents(
             "CPU_ERR2", host_error_monitor::err2Handler,