1 #include <libpdbg.h> 2 3 #include <phosphor-logging/log.hpp> 4 #include <sdbusplus/bus.hpp> 5 6 #include <iomanip> 7 8 using namespace phosphor::logging; 9 10 namespace attn 11 { 12 13 /** 14 * @brief Handle SBE vital attention 15 * 16 * @return 0 = success 17 */ 18 int handleVital(); 19 20 /** 21 * @brief Handle checkstop attention 22 * 23 * @return 0 = success 24 */ 25 int handleCheckstop(); 26 27 /** 28 * @brief Handle special attention 29 * 30 * @param i_breakpoints true = breakpoint special attn handling enabled 31 * @return 0 = success 32 */ 33 int handleSpecial(bool i_breakpoints); 34 35 /** 36 * @brief Notify Cronus over dbus interface 37 * 38 * @param i_proc Processor number with Special attention 39 * @param i_core Core number with special attention 40 * @param i_thread Thread number with special attention 41 */ 42 void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread); 43 44 /** 45 * @brief Start host diagnostic mode 46 * 47 * Start the host diagnostic mode systemd unit 48 */ 49 void startHostDiagnosticMode(); 50 51 /** 52 * @brief The main attention handler logic 53 * 54 * @param i_breakpoints true = breakpoint special attn handling enabled 55 */ 56 void attnHandler(bool i_breakpoints) 57 { 58 uint32_t isr_val, isr_mask; 59 uint32_t proc; 60 61 // loop through processors looking for active attentions 62 pdbg_target* target; 63 pdbg_for_each_class_target("fsi", target) 64 { 65 if (PDBG_TARGET_ENABLED == pdbg_target_probe(target)) 66 { 67 proc = pdbg_target_index(target); // get processor number 68 69 std::stringstream ss; // log message stream 70 ss << "[ATTN] checking processor " << proc << std::endl; 71 log<level::INFO>(ss.str().c_str()); 72 73 // get active attentions on processor 74 if (0 != fsi_read(target, 0x1007, &isr_val)) 75 { 76 std::stringstream ss; // log message stream 77 ss << "[ATTN] Error! cfam read 0x1007 FAILED" << std::endl; 78 log<level::INFO>(ss.str().c_str()); 79 } 80 else 81 { 82 std::stringstream ss; // log message stream 83 ss << "[ATTN] cfam 0x1007 = 0x"; 84 ss << std::hex << std::setw(8) << std::setfill('0'); 85 ss << isr_val << std::endl; 86 log<level::INFO>(ss.str().c_str()); 87 88 // get interrupt enabled special attentions mask 89 if (0 != fsi_read(target, 0x100d, &isr_mask)) 90 { 91 std::stringstream ss; // log message stream 92 ss << "[ATTN] Error! cfam read 0x100d FAILED" << std::endl; 93 log<level::INFO>(ss.str().c_str()); 94 } 95 else 96 { 97 std::stringstream ss; // log message stream 98 ss << "[ATTN] cfam 0x100d = 0x"; 99 ss << std::hex << std::setw(8) << std::setfill('0'); 100 ss << isr_mask << std::endl; 101 log<level::INFO>(ss.str().c_str()); 102 103 // bit 0 on "left": bit 30 = SBE vital attention 104 if (isr_val & isr_mask & 0x00000002) 105 { 106 handleVital(); 107 } 108 109 // bit 0 on "left": bit 1 = checkstop 110 if (isr_val & isr_mask & 0x40000000) 111 { 112 handleCheckstop(); 113 } 114 115 // bit 0 on "left": bit 2 = special attention 116 if (isr_val & isr_mask & 0x20000000) 117 { 118 handleSpecial(i_breakpoints); 119 } 120 } // cfam 0x100d valid 121 } // cfam 0x1007 valid 122 } // fsi target enabled 123 } // next processor 124 125 return; // checked all processors 126 } 127 128 /** 129 * @brief Handle SBE vital attention 130 */ 131 int handleVital() 132 { 133 int rc = 1; // vital attention handling not yet supported 134 135 std::stringstream ss; // log message stream 136 ss << "[ATTN] vital" << std::endl; 137 log<level::INFO>(ss.str().c_str()); 138 139 if (0 != rc) 140 { 141 std::stringstream ss; // log message stream 142 ss << "[ATTN] vital NOT handled" << std::endl; 143 log<level::INFO>(ss.str().c_str()); 144 } 145 146 return rc; 147 } 148 149 /** 150 * @brief Handle checkstop attention 151 */ 152 int handleCheckstop() 153 { 154 int rc = 1; // checkstop handling not yet supported 155 156 std::stringstream ss; // log message stream 157 ss << "[ATTN] checkstop" << std::endl; 158 log<level::INFO>(ss.str().c_str()); 159 160 if (0 != rc) 161 { 162 std::stringstream ss; // log message stream 163 ss << "[ATTN] checkstop NOT handled" << std::endl; 164 log<level::INFO>(ss.str().c_str()); 165 } 166 167 // TODO recoverable errors? 168 169 return rc; 170 } 171 172 /** 173 * @brief Handle special attention 174 * 175 * @param i_breakpoints true = breakpoint special attn handling enabled 176 */ 177 int handleSpecial(bool i_breakpoints) 178 { 179 int rc = 0; // special attention handling supported 180 181 std::stringstream ss; // log message stream 182 183 ss << "[ATTN] special" << std::endl; 184 185 // Right now we always handle breakpoint special attentions if breakpoint 186 // attn handling is enabled. This will eventually check if breakpoint attn 187 // handing is enabled AND there is a breakpoint pending. 188 if (true == i_breakpoints) 189 { 190 ss << "[ATTN] breakpoint" << std::endl; 191 log<level::INFO>(ss.str().c_str()); 192 193 // Cronus will determine proc, core and thread so just notify 194 notifyCronus(0, 0, 0); // proc-0, core-0, thread-0 195 } 196 // Right now if breakpoint attn handling is not enabled we will treat the 197 // special attention as a TI. This will eventually be changed to check 198 // whether a TI is active and handle it regardless of whether breakpoint 199 // handling is enbaled or not. 200 else 201 { 202 ss << "[ATTN] TI (terminate immediately)" << std::endl; 203 log<level::INFO>(ss.str().c_str()); 204 205 // Start host diagnostic mode 206 startHostDiagnosticMode(); 207 } 208 209 // TODO recoverable errors? 210 211 return rc; 212 } 213 214 /** 215 * @brief Notify Cronus over dbus interface 216 */ 217 void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread) 218 { 219 std::stringstream ss; // log message stream 220 221 // log status info 222 ss << "[ATTN] notify "; 223 ss << i_proc << ", " << i_core << ", " << i_thread << std::endl; 224 log<level::INFO>(ss.str().c_str()); 225 226 // notify Cronus over dbus 227 auto bus = sdbusplus::bus::new_system(); 228 auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt"); 229 230 std::array<uint32_t, 3> params{i_proc, i_core, i_thread}; 231 msg.append(params); 232 233 msg.signal_send(); 234 235 return; 236 } 237 238 /** 239 * @brief Start host diagnostic mode 240 * */ 241 void startHostDiagnosticMode() 242 { 243 std::stringstream ss; // log message stream 244 245 // log status info 246 ss << "[ATTN] start host diagnostic mode service" << std::endl; 247 log<level::INFO>(ss.str().c_str()); 248 249 // Use the systemd service manager object interface to call the start unit 250 // method with the obmc-host-diagnostic-mode target. 251 auto bus = sdbusplus::bus::new_system(); 252 auto method = bus.new_method_call( 253 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 254 "org.freedesktop.systemd1.Manager", "StartUnit"); 255 256 method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate 257 method.append("replace"); // mode = replace conflicting queued jobs 258 bus.call_noreply(method); // start the service 259 260 return; 261 } 262 263 } // namespace attn 264