Handling for host detected LPC timeout

For reasons not explained yet, hardware will not initiate an LPC timeout
attention via NCU timeout FIR bit as we expected. When the host firmware
detects an LPC timeout, it will manually set N1_LOCAL_FIR[61] to force a
system checkstop. The service response for this bit will be to call out
the hardware as if there was a hardware reported LPC timeout.

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I863e8aa3ef50a4b18b5106b3a45c4cf81b2c7808
diff --git a/analyzer/plugins/p10-plugins.cpp b/analyzer/plugins/p10-plugins.cpp
index a3ac1ca..2ae9ff7 100644
--- a/analyzer/plugins/p10-plugins.cpp
+++ b/analyzer/plugins/p10-plugins.cpp
@@ -59,6 +59,37 @@
     }
 }
 
+void lpc_timeout_callout(const libhei::Chip& i_chip, ServiceData& io_servData)
+{
+    auto target = util::pdbg::getTrgt(i_chip);
+    auto path   = util::pdbg::getPath(target);
+
+    // Callout the PNOR.
+    io_servData.calloutPart(callout::PartType::PNOR, callout::Priority::MED);
+
+    // Callout the associated clock, no guard.
+    auto chipPos = util::pdbg::getChipPos(target);
+    if (0 == chipPos)
+    {
+        // Clock 0 is hardwired to proc 0.
+        io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_0,
+                                 callout::Priority::MED, false);
+    }
+    else if (1 == chipPos)
+    {
+        // Clock 1 is hardwired to proc 1.
+        io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_1,
+                                 callout::Priority::MED, false);
+    }
+    else
+    {
+        trace::err("LPC timeout on unexpected processor: %s", path);
+    }
+
+    // Callout the processor, no guard.
+    io_servData.calloutTarget(target, callout::Priority::MED, false);
+}
+
 /**
  * @brief Queries for an LPC timeout. If present, will callout all appropriate
  *        hardware.
@@ -73,31 +104,7 @@
     {
         trace::inf("LPC timeout detected on %s", path);
 
-        // Callout the PNOR.
-        io_servData.calloutPart(callout::PartType::PNOR,
-                                callout::Priority::MED);
-
-        // Callout the associated clock, no guard.
-        auto chipPos = util::pdbg::getChipPos(target);
-        if (0 == chipPos)
-        {
-            // Clock 0 is hardwired to proc 0.
-            io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_0,
-                                     callout::Priority::MED, false);
-        }
-        else if (1 == chipPos)
-        {
-            // Clock 1 is hardwired to proc 1.
-            io_servData.calloutClock(callout::ClockType::OSC_REF_CLOCK_1,
-                                     callout::Priority::MED, false);
-        }
-        else
-        {
-            trace::err("LPC timeout on unexpected processor: %s", path);
-        }
-
-        // Callout the processor, no guard.
-        io_servData.calloutTarget(target, callout::Priority::MED, false);
+        lpc_timeout_callout(i_chip, io_servData);
     }
     else
     {
@@ -108,6 +115,20 @@
     }
 }
 
+/**
+ * @brief If Hostboot detects an LPC timeout, it will manually trigger a
+ *        checkstop attention. We will have to bypass checking for an LPC
+ *        timeout via the HWP because it will not find the timeout. Instead,
+ *        simply make the callout when Hostboot triggers the attention.
+ */
+void lpc_timeout_workaround(unsigned int, const libhei::Chip& i_chip,
+                            ServiceData& io_servData)
+{
+    trace::inf("Host detected LPC timeout %s", util::pdbg::getPath(i_chip));
+
+    lpc_timeout_callout(i_chip, io_servData);
+}
+
 } // namespace P10
 
 PLUGIN_DEFINE_NS(P10_10, P10, pll_unlock);
@@ -116,4 +137,7 @@
 PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout);
 PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout);
 
+PLUGIN_DEFINE_NS(P10_10, P10, lpc_timeout_workaround);
+PLUGIN_DEFINE_NS(P10_20, P10, lpc_timeout_workaround);
+
 } // namespace analyzer
diff --git a/analyzer/ras-data/data/ras-data-p10-10.json b/analyzer/ras-data/data/ras-data-p10-10.json
index 62e1636..9a53817 100644
--- a/analyzer/ras-data/data/ras-data-p10-10.json
+++ b/analyzer/ras-data/data/ras-data-p10-10.json
@@ -1001,6 +1001,10 @@
             { "type": "plugin", "name": "lpc_timeout", "instance": 0 }
         ],
 
+        "host_detected_lpc_timeout"    : [
+            { "type": "plugin", "name": "lpc_timeout_workaround", "instance": 0 }
+        ],
+
         "master_power_bus_chip_procedure": [
             { "type": "action", "name": "level2" }
         ],
@@ -19668,7 +19672,7 @@
          "3a" : { "00" : "deadman_timer" },
          "3b" : { "00" : "self" },
          "3c" : { "00" : "level2" },
-         "3d" : { "00" : "masked" },
+         "3d" : { "00" : "host_detected_lpc_timeout" },
          "3e" : { "00" : "masked" },
          "3f" : { "00" : "masked" }
       },
diff --git a/analyzer/ras-data/data/ras-data-p10-20.json b/analyzer/ras-data/data/ras-data-p10-20.json
index c0bd2e5..c6a0266 100644
--- a/analyzer/ras-data/data/ras-data-p10-20.json
+++ b/analyzer/ras-data/data/ras-data-p10-20.json
@@ -1001,6 +1001,10 @@
             { "type": "plugin", "name": "lpc_timeout", "instance": 0 }
         ],
 
+        "host_detected_lpc_timeout"    : [
+            { "type": "plugin", "name": "lpc_timeout_workaround", "instance": 0 }
+        ],
+
         "master_power_bus_chip_procedure": [
             { "type": "action", "name": "level2" }
         ],
@@ -19642,7 +19646,7 @@
          "3a" : { "00" : "deadman_timer" },
          "3b" : { "00" : "self" },
          "3c" : { "00" : "level2" },
-         "3d" : { "00" : "masked" },
+         "3d" : { "00" : "host_detected_lpc_timeout" },
          "3e" : { "00" : "masked" },
          "3f" : { "00" : "masked" }
       },