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