1ef320154SBen Tyner #include <libpdbg.h>
2ef320154SBen Tyner 
3*0205f3b3SBen Tyner #include <analyzer/analyzer_main.hpp>
4ef320154SBen Tyner #include <phosphor-logging/log.hpp>
5ef320154SBen Tyner #include <sdbusplus/bus.hpp>
6ef320154SBen Tyner 
7ef320154SBen Tyner #include <iomanip>
8ef320154SBen Tyner 
9ef320154SBen Tyner using namespace phosphor::logging;
10ef320154SBen Tyner 
11ef320154SBen Tyner namespace attn
12ef320154SBen Tyner {
13ef320154SBen Tyner 
14ef320154SBen Tyner /**
15ef320154SBen Tyner  * @brief Handle SBE vital attention
16ef320154SBen Tyner  *
17ef320154SBen Tyner  * @return 0 = success
18ef320154SBen Tyner  */
19ef320154SBen Tyner int handleVital();
20ef320154SBen Tyner 
21ef320154SBen Tyner /**
22ef320154SBen Tyner  * @brief Handle checkstop attention
23ef320154SBen Tyner  *
24ef320154SBen Tyner  * @return 0 = success
25ef320154SBen Tyner  */
26ef320154SBen Tyner int handleCheckstop();
27ef320154SBen Tyner 
28ef320154SBen Tyner /**
29ef320154SBen Tyner  * @brief Handle special attention
30ef320154SBen Tyner  *
31970fd4fbSBen Tyner  * @param i_breakpoints true = breakpoint special attn handling enabled
32ef320154SBen Tyner  * @return 0 = success
33ef320154SBen Tyner  */
34970fd4fbSBen Tyner int handleSpecial(bool i_breakpoints);
35ef320154SBen Tyner 
36ef320154SBen Tyner /**
37ef320154SBen Tyner  * @brief Notify Cronus over dbus interface
38ef320154SBen Tyner  *
39ef320154SBen Tyner  * @param i_proc   Processor number with Special attention
40ef320154SBen Tyner  * @param i_core   Core number with special attention
41ef320154SBen Tyner  * @param i_thread Thread number with special attention
42ef320154SBen Tyner  */
43ef320154SBen Tyner void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread);
44ef320154SBen Tyner 
45ef320154SBen Tyner /**
467e6611f9SBen Tyner  * @brief Start host diagnostic mode
477e6611f9SBen Tyner  *
487e6611f9SBen Tyner  * Start the host diagnostic mode systemd unit
497e6611f9SBen Tyner  */
507e6611f9SBen Tyner void startHostDiagnosticMode();
517e6611f9SBen Tyner 
527e6611f9SBen Tyner /**
53ef320154SBen Tyner  * @brief The main attention handler logic
54970fd4fbSBen Tyner  *
55970fd4fbSBen Tyner  * @param i_breakpoints true = breakpoint special attn handling enabled
56ef320154SBen Tyner  */
57970fd4fbSBen Tyner void attnHandler(bool i_breakpoints)
58ef320154SBen Tyner {
59ef320154SBen Tyner     uint32_t isr_val, isr_mask;
60ef320154SBen Tyner     uint32_t proc;
61ef320154SBen Tyner 
62ef320154SBen Tyner     // loop through processors looking for active attentions
63ef320154SBen Tyner     pdbg_target* target;
64ef320154SBen Tyner     pdbg_for_each_class_target("fsi", target)
65ef320154SBen Tyner     {
66ef320154SBen Tyner         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
67ef320154SBen Tyner         {
68ef320154SBen Tyner             proc = pdbg_target_index(target); // get processor number
69ef320154SBen Tyner 
70ef320154SBen Tyner             std::stringstream ss; // log message stream
71ef320154SBen Tyner             ss << "[ATTN] checking processor " << proc << std::endl;
72ef320154SBen Tyner             log<level::INFO>(ss.str().c_str());
73ef320154SBen Tyner 
74ef320154SBen Tyner             // get active attentions on processor
75ef320154SBen Tyner             if (0 != fsi_read(target, 0x1007, &isr_val))
76ef320154SBen Tyner             {
77ef320154SBen Tyner                 std::stringstream ss; // log message stream
78ef320154SBen Tyner                 ss << "[ATTN] Error! cfam read 0x1007 FAILED" << std::endl;
79ef320154SBen Tyner                 log<level::INFO>(ss.str().c_str());
80ef320154SBen Tyner             }
81ef320154SBen Tyner             else
82ef320154SBen Tyner             {
83ef320154SBen Tyner                 std::stringstream ss; // log message stream
84ef320154SBen Tyner                 ss << "[ATTN] cfam 0x1007 = 0x";
85ef320154SBen Tyner                 ss << std::hex << std::setw(8) << std::setfill('0');
86ef320154SBen Tyner                 ss << isr_val << std::endl;
87ef320154SBen Tyner                 log<level::INFO>(ss.str().c_str());
88ef320154SBen Tyner 
89ef320154SBen Tyner                 // get interrupt enabled special attentions mask
90ef320154SBen Tyner                 if (0 != fsi_read(target, 0x100d, &isr_mask))
91ef320154SBen Tyner                 {
92ef320154SBen Tyner                     std::stringstream ss; // log message stream
93ef320154SBen Tyner                     ss << "[ATTN] Error! cfam read 0x100d FAILED" << std::endl;
94ef320154SBen Tyner                     log<level::INFO>(ss.str().c_str());
95ef320154SBen Tyner                 }
96ef320154SBen Tyner                 else
97ef320154SBen Tyner                 {
98ef320154SBen Tyner                     std::stringstream ss; // log message stream
99ef320154SBen Tyner                     ss << "[ATTN] cfam 0x100d = 0x";
100ef320154SBen Tyner                     ss << std::hex << std::setw(8) << std::setfill('0');
101ef320154SBen Tyner                     ss << isr_mask << std::endl;
102ef320154SBen Tyner                     log<level::INFO>(ss.str().c_str());
103ef320154SBen Tyner 
104ef320154SBen Tyner                     // bit 0 on "left": bit 30 = SBE vital attention
105ef320154SBen Tyner                     if (isr_val & isr_mask & 0x00000002)
106ef320154SBen Tyner                     {
107ef320154SBen Tyner                         handleVital();
108ef320154SBen Tyner                     }
109ef320154SBen Tyner 
110ef320154SBen Tyner                     // bit 0 on "left": bit 1 = checkstop
111ef320154SBen Tyner                     if (isr_val & isr_mask & 0x40000000)
112ef320154SBen Tyner                     {
113ef320154SBen Tyner                         handleCheckstop();
114ef320154SBen Tyner                     }
115ef320154SBen Tyner 
116ef320154SBen Tyner                     // bit 0 on "left": bit 2 = special attention
117ef320154SBen Tyner                     if (isr_val & isr_mask & 0x20000000)
118ef320154SBen Tyner                     {
119970fd4fbSBen Tyner                         handleSpecial(i_breakpoints);
120ef320154SBen Tyner                     }
121ef320154SBen Tyner                 } // cfam 0x100d valid
122ef320154SBen Tyner             }     // cfam 0x1007 valid
123ef320154SBen Tyner         }         // fsi target enabled
124ef320154SBen Tyner     }             // next processor
125ef320154SBen Tyner 
126ef320154SBen Tyner     return; // checked all processors
127ef320154SBen Tyner }
128ef320154SBen Tyner 
129ef320154SBen Tyner /**
130ef320154SBen Tyner  * @brief Handle SBE vital attention
131ef320154SBen Tyner  */
132ef320154SBen Tyner int handleVital()
133ef320154SBen Tyner {
134ef320154SBen Tyner     int rc = 1; // vital attention handling not yet supported
135ef320154SBen Tyner 
136ef320154SBen Tyner     std::stringstream ss; // log message stream
137ef320154SBen Tyner     ss << "[ATTN] vital" << std::endl;
138ef320154SBen Tyner     log<level::INFO>(ss.str().c_str());
139ef320154SBen Tyner 
140ef320154SBen Tyner     if (0 != rc)
141ef320154SBen Tyner     {
142ef320154SBen Tyner         std::stringstream ss; // log message stream
143ef320154SBen Tyner         ss << "[ATTN] vital NOT handled" << std::endl;
144ef320154SBen Tyner         log<level::INFO>(ss.str().c_str());
145ef320154SBen Tyner     }
146ef320154SBen Tyner 
147ef320154SBen Tyner     return rc;
148ef320154SBen Tyner }
149ef320154SBen Tyner 
150ef320154SBen Tyner /**
151ef320154SBen Tyner  * @brief Handle checkstop attention
152ef320154SBen Tyner  */
153ef320154SBen Tyner int handleCheckstop()
154ef320154SBen Tyner {
155ef320154SBen Tyner     int rc = 1; // checkstop handling not yet supported
156ef320154SBen Tyner 
157ef320154SBen Tyner     std::stringstream ss; // log message stream
158ef320154SBen Tyner     ss << "[ATTN] checkstop" << std::endl;
159ef320154SBen Tyner     log<level::INFO>(ss.str().c_str());
160ef320154SBen Tyner 
161*0205f3b3SBen Tyner     analyzer::analyzeHardware();
162ef320154SBen Tyner 
163ef320154SBen Tyner     // TODO recoverable errors?
164ef320154SBen Tyner 
165ef320154SBen Tyner     return rc;
166ef320154SBen Tyner }
167ef320154SBen Tyner 
168ef320154SBen Tyner /**
169ef320154SBen Tyner  * @brief Handle special attention
170970fd4fbSBen Tyner  *
171970fd4fbSBen Tyner  * @param i_breakpoints true = breakpoint special attn handling enabled
172ef320154SBen Tyner  */
173970fd4fbSBen Tyner int handleSpecial(bool i_breakpoints)
174ef320154SBen Tyner {
175ef320154SBen Tyner     int rc = 0; // special attention handling supported
176ef320154SBen Tyner 
177ef320154SBen Tyner     std::stringstream ss; // log message stream
178ef320154SBen Tyner 
179ef320154SBen Tyner     ss << "[ATTN] special" << std::endl;
180ef320154SBen Tyner 
181970fd4fbSBen Tyner     // Right now we always handle breakpoint special attentions if breakpoint
182970fd4fbSBen Tyner     // attn handling is enabled. This will eventually check if breakpoint attn
183970fd4fbSBen Tyner     // handing is enabled AND there is a breakpoint pending.
184970fd4fbSBen Tyner     if (true == i_breakpoints)
185970fd4fbSBen Tyner     {
186970fd4fbSBen Tyner         ss << "[ATTN] breakpoint" << std::endl;
187970fd4fbSBen Tyner         log<level::INFO>(ss.str().c_str());
188ef320154SBen Tyner 
189ef320154SBen Tyner         // Cronus will determine proc, core and thread so just notify
190970fd4fbSBen Tyner         notifyCronus(0, 0, 0); // proc-0, core-0, thread-0
191970fd4fbSBen Tyner     }
192970fd4fbSBen Tyner     // Right now if breakpoint attn handling is not enabled we will treat the
193970fd4fbSBen Tyner     // special attention as a TI. This will eventually be changed to check
194970fd4fbSBen Tyner     // whether a TI is active and handle it regardless of whether breakpoint
195970fd4fbSBen Tyner     // handling is enbaled or not.
196970fd4fbSBen Tyner     else
197970fd4fbSBen Tyner     {
1987e6611f9SBen Tyner         ss << "[ATTN] TI (terminate immediately)" << std::endl;
1997e6611f9SBen Tyner         log<level::INFO>(ss.str().c_str());
200970fd4fbSBen Tyner 
201970fd4fbSBen Tyner         // Start host diagnostic mode
2027e6611f9SBen Tyner         startHostDiagnosticMode();
203970fd4fbSBen Tyner     }
204ef320154SBen Tyner 
205ef320154SBen Tyner     // TODO recoverable errors?
206ef320154SBen Tyner 
207ef320154SBen Tyner     return rc;
208ef320154SBen Tyner }
209ef320154SBen Tyner 
210ef320154SBen Tyner /**
211ef320154SBen Tyner  * @brief Notify Cronus over dbus interface
212ef320154SBen Tyner  */
213ef320154SBen Tyner void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread)
214ef320154SBen Tyner {
215ef320154SBen Tyner     std::stringstream ss; // log message stream
216ef320154SBen Tyner 
217ef320154SBen Tyner     // log status info
218ef320154SBen Tyner     ss << "[ATTN] notify ";
219ef320154SBen Tyner     ss << i_proc << ", " << i_core << ", " << i_thread << std::endl;
220ef320154SBen Tyner     log<level::INFO>(ss.str().c_str());
221ef320154SBen Tyner 
222ef320154SBen Tyner     // notify Cronus over dbus
223ef320154SBen Tyner     auto bus = sdbusplus::bus::new_system();
224ef320154SBen Tyner     auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt");
225ef320154SBen Tyner 
226ef320154SBen Tyner     std::array<uint32_t, 3> params{i_proc, i_core, i_thread};
227ef320154SBen Tyner     msg.append(params);
228ef320154SBen Tyner 
229ef320154SBen Tyner     msg.signal_send();
2307e6611f9SBen Tyner 
2317e6611f9SBen Tyner     return;
2327e6611f9SBen Tyner }
2337e6611f9SBen Tyner 
2347e6611f9SBen Tyner /**
2357e6611f9SBen Tyner  * @brief Start host diagnostic mode
2367e6611f9SBen Tyner  * */
2377e6611f9SBen Tyner void startHostDiagnosticMode()
2387e6611f9SBen Tyner {
2397e6611f9SBen Tyner     std::stringstream ss; // log message stream
2407e6611f9SBen Tyner 
2417e6611f9SBen Tyner     // log status info
2427e6611f9SBen Tyner     ss << "[ATTN] start host diagnostic mode service" << std::endl;
2437e6611f9SBen Tyner     log<level::INFO>(ss.str().c_str());
2447e6611f9SBen Tyner 
2457e6611f9SBen Tyner     // Use the systemd service manager object interface to call the start unit
2467e6611f9SBen Tyner     // method with the obmc-host-diagnostic-mode target.
2477e6611f9SBen Tyner     auto bus    = sdbusplus::bus::new_system();
2487e6611f9SBen Tyner     auto method = bus.new_method_call(
2497e6611f9SBen Tyner         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
2507e6611f9SBen Tyner         "org.freedesktop.systemd1.Manager", "StartUnit");
2517e6611f9SBen Tyner 
2527e6611f9SBen Tyner     method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate
2537e6611f9SBen Tyner     method.append("replace"); // mode = replace conflicting queued jobs
2547e6611f9SBen Tyner     bus.call_noreply(method); // start the service
2557e6611f9SBen Tyner 
2567e6611f9SBen Tyner     return;
257ef320154SBen Tyner }
258ef320154SBen Tyner 
259ef320154SBen Tyner } // namespace attn
260