#include #include #include #include #include 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 * * @param i_breakpoints true = breakpoint special attn handling enabled * @return 0 = success */ int handleSpecial(bool i_breakpoints); /** * @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 Start host diagnostic mode * * Start the host diagnostic mode systemd unit */ void startHostDiagnosticMode(); /** * @brief The main attention handler logic * * @param i_breakpoints true = breakpoint special attn handling enabled */ void attnHandler(bool i_breakpoints) { 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(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(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(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(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(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(i_breakpoints); } } // 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(ss.str().c_str()); if (0 != rc) { std::stringstream ss; // log message stream ss << "[ATTN] vital NOT handled" << std::endl; log(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(ss.str().c_str()); analyzer::analyzeHardware(); // TODO recoverable errors? return rc; } /** * @brief Handle special attention * * @param i_breakpoints true = breakpoint special attn handling enabled */ int handleSpecial(bool i_breakpoints) { int rc = 0; // special attention handling supported std::stringstream ss; // log message stream ss << "[ATTN] special" << std::endl; // Right now we always handle breakpoint special attentions if breakpoint // attn handling is enabled. This will eventually check if breakpoint attn // handing is enabled AND there is a breakpoint pending. if (true == i_breakpoints) { ss << "[ATTN] breakpoint" << std::endl; log(ss.str().c_str()); // Cronus will determine proc, core and thread so just notify notifyCronus(0, 0, 0); // proc-0, core-0, thread-0 } // Right now if breakpoint attn handling is not enabled we will treat the // special attention as a TI. This will eventually be changed to check // whether a TI is active and handle it regardless of whether breakpoint // handling is enbaled or not. else { ss << "[ATTN] TI (terminate immediately)" << std::endl; log(ss.str().c_str()); // Start host diagnostic mode startHostDiagnosticMode(); } // 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(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 params{i_proc, i_core, i_thread}; msg.append(params); msg.signal_send(); return; } /** * @brief Start host diagnostic mode * */ void startHostDiagnosticMode() { std::stringstream ss; // log message stream // log status info ss << "[ATTN] start host diagnostic mode service" << std::endl; log(ss.str().c_str()); // Use the systemd service manager object interface to call the start unit // method with the obmc-host-diagnostic-mode target. auto bus = sdbusplus::bus::new_system(); auto method = bus.new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"); method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate method.append("replace"); // mode = replace conflicting queued jobs bus.call_noreply(method); // start the service return; } } // namespace attn