Attention Handler base logic

Added base logic for the attention handler application (attn) as a starting point for further refinement. Attn will handle SBE vital, system checkstop and special attention events. These events will be handled through a combination local logic and external hardware and software interfaces.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I074fb86474761bf694644c71d93ede9c45673b79
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
new file mode 100644
index 0000000..cac1f84
--- /dev/null
+++ b/attn/attn_handler.cpp
@@ -0,0 +1,207 @@
+#include <libpdbg.h>
+
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <iomanip>
+
+using namespace phosphor::logging;
+
+namespace attn
+{
+
+/**
+ * @brief Handle SBE vital attention
+ *
+ * @return 0 = success
+ */
+int handleVital();
+
+/**
+ * @brief Handle checkstop attention
+ *
+ * @return 0 = success
+ */
+int handleCheckstop();
+
+/**
+ * @brief Handle special attention
+ *
+ * @return 0 = success
+ */
+int handleSpecial();
+
+/**
+ * @brief Notify Cronus over dbus interface
+ *
+ * @param i_proc   Processor number with Special attention
+ * @param i_core   Core number with special attention
+ * @param i_thread Thread number with special attention
+ */
+void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread);
+
+/**
+ * @brief The main attention handler logic
+ */
+void attnHandler()
+{
+    uint32_t isr_val, isr_mask;
+    uint32_t proc;
+
+    // loop through processors looking for active attentions
+    pdbg_target* target;
+    pdbg_for_each_class_target("fsi", target)
+    {
+        if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
+        {
+            proc = pdbg_target_index(target); // get processor number
+
+            std::stringstream ss; // log message stream
+            ss << "[ATTN] checking processor " << proc << std::endl;
+            log<level::INFO>(ss.str().c_str());
+
+            // get active attentions on processor
+            if (0 != fsi_read(target, 0x1007, &isr_val))
+            {
+                std::stringstream ss; // log message stream
+                ss << "[ATTN] Error! cfam read 0x1007 FAILED" << std::endl;
+                log<level::INFO>(ss.str().c_str());
+            }
+            else
+            {
+                std::stringstream ss; // log message stream
+                ss << "[ATTN] cfam 0x1007 = 0x";
+                ss << std::hex << std::setw(8) << std::setfill('0');
+                ss << isr_val << std::endl;
+                log<level::INFO>(ss.str().c_str());
+
+                // get interrupt enabled special attentions mask
+                if (0 != fsi_read(target, 0x100d, &isr_mask))
+                {
+                    std::stringstream ss; // log message stream
+                    ss << "[ATTN] Error! cfam read 0x100d FAILED" << std::endl;
+                    log<level::INFO>(ss.str().c_str());
+                }
+                else
+                {
+                    std::stringstream ss; // log message stream
+                    ss << "[ATTN] cfam 0x100d = 0x";
+                    ss << std::hex << std::setw(8) << std::setfill('0');
+                    ss << isr_mask << std::endl;
+                    log<level::INFO>(ss.str().c_str());
+
+                    // bit 0 on "left": bit 30 = SBE vital attention
+                    if (isr_val & isr_mask & 0x00000002)
+                    {
+                        handleVital();
+                    }
+
+                    // bit 0 on "left": bit 1 = checkstop
+                    if (isr_val & isr_mask & 0x40000000)
+                    {
+                        handleCheckstop();
+                    }
+
+                    // bit 0 on "left": bit 2 = special attention
+                    if (isr_val & isr_mask & 0x20000000)
+                    {
+                        handleSpecial();
+                    }
+                } // cfam 0x100d valid
+            }     // cfam 0x1007 valid
+        }         // fsi target enabled
+    }             // next processor
+
+    return; // checked all processors
+}
+
+/**
+ * @brief Handle SBE vital attention
+ */
+int handleVital()
+{
+    int rc = 1; // vital attention handling not yet supported
+
+    std::stringstream ss; // log message stream
+    ss << "[ATTN] vital" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    if (0 != rc)
+    {
+        std::stringstream ss; // log message stream
+        ss << "[ATTN] vital NOT handled" << std::endl;
+        log<level::INFO>(ss.str().c_str());
+    }
+
+    return rc;
+}
+
+/**
+ * @brief Handle checkstop attention
+ */
+int handleCheckstop()
+{
+    int rc = 1; // checkstop handling not yet supported
+
+    std::stringstream ss; // log message stream
+    ss << "[ATTN] checkstop" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    if (0 != rc)
+    {
+        std::stringstream ss; // log message stream
+        ss << "[ATTN] checkstop NOT handled" << std::endl;
+        log<level::INFO>(ss.str().c_str());
+    }
+
+    // TODO recoverable errors?
+
+    return rc;
+}
+
+/**
+ * @brief Handle special attention
+ */
+int handleSpecial()
+{
+    int rc = 0; // special attention handling supported
+
+    std::stringstream ss; // log message stream
+
+    ss << "[ATTN] special" << std::endl;
+
+    // Currently we are only handling Cronus breakpoints
+    ss << "[ATTN] breakpoint" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // Cronus will determine proc, core and thread so just notify
+    notifyCronus(0, 0, 0); // proc-0, core-0, thread-0
+
+    // TODO recoverable errors?
+
+    return rc;
+}
+
+/**
+ * @brief Notify Cronus over dbus interface
+ */
+void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread)
+{
+    std::stringstream ss; // log message stream
+
+    // log status info
+    ss << "[ATTN] notify ";
+    ss << i_proc << ", " << i_core << ", " << i_thread << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // notify Cronus over dbus
+    auto bus = sdbusplus::bus::new_system();
+    auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt");
+
+    std::array<uint32_t, 3> params{i_proc, i_core, i_thread};
+    msg.append(params);
+
+    msg.signal_send();
+}
+
+} // namespace attn