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