1 #include "config.h"
2
3 #include "mihawk-cpld.hpp"
4
5 #include "gpio.hpp"
6 #include "utility.hpp"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/ioctl.h>
11 #include <unistd.h>
12
13 #include <elog-errors.hpp>
14 #include <org/open_power/Witherspoon/Fault/error.hpp>
15 #include <phosphor-logging/elog.hpp>
16 #include <phosphor-logging/log.hpp>
17 #include <xyz/openbmc_project/Common/Device/error.hpp>
18
19 #include <chrono>
20 #include <iostream>
21 #include <map>
22 #include <memory>
23 #include <string>
24
25 // i2c bus & i2c slave address of Mihawk's CPLD_register
26 static constexpr uint8_t busId = 11;
27 static constexpr uint8_t slaveAddr = 0x40;
28
29 // SMLink Status Register(PSU status Register)
30 static constexpr size_t StatusReg_0 = 0x05;
31
32 // SMLink Status Register(Interrupt-control-bit Register)
33 static constexpr size_t StatusReg_1 = 0x20;
34
35 // SMLink Status Register(Power-on error code Register)
36 static constexpr size_t StatusReg_2 = 0x21;
37
38 // SMLink Status Register(Power-ready error code Register)
39 static constexpr size_t StatusReg_3 = 0x22;
40
41 using namespace std;
42
43 namespace phosphor
44 {
45 namespace power
46 {
47 const auto DEVICE_NAME = "MihawkCPLD"s;
48
49 namespace fs = std::filesystem;
50 using namespace phosphor::logging;
51
52 using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
53
MihawkCPLD(size_t instance,sdbusplus::bus_t & bus)54 MihawkCPLD::MihawkCPLD(size_t instance, sdbusplus::bus_t& bus) :
55 Device(DEVICE_NAME, instance), bus(bus)
56 {}
57
onFailure()58 void MihawkCPLD::onFailure()
59 {
60 bool poweronError = checkPoweronFault();
61
62 // If the interrupt of power_on_error is switch on,
63 // read CPLD_register error code to analyze
64 // and report the error log event.
65 if (poweronError)
66 {
67 ErrorCode code;
68 code = static_cast<ErrorCode>(readFromCPLDErrorCode(StatusReg_2));
69
70 switch (code)
71 {
72 case ErrorCode::_1:
73 report<ErrorCode1>();
74 break;
75 case ErrorCode::_2:
76 report<ErrorCode2>();
77 break;
78 case ErrorCode::_3:
79 report<ErrorCode3>();
80 break;
81 case ErrorCode::_4:
82 report<ErrorCode4>();
83 break;
84 case ErrorCode::_5:
85 report<ErrorCode5>();
86 break;
87 case ErrorCode::_6:
88 report<ErrorCode6>();
89 break;
90 case ErrorCode::_7:
91 report<ErrorCode7>();
92 break;
93 case ErrorCode::_8:
94 report<ErrorCode8>();
95 break;
96 case ErrorCode::_9:
97 report<ErrorCode9>();
98 break;
99 case ErrorCode::_10:
100 report<ErrorCode10>();
101 break;
102 case ErrorCode::_11:
103 report<ErrorCode11>();
104 break;
105 case ErrorCode::_12:
106 report<ErrorCode12>();
107 break;
108 case ErrorCode::_13:
109 report<ErrorCode13>();
110 break;
111 case ErrorCode::_14:
112 report<ErrorCode14>();
113 break;
114 case ErrorCode::_15:
115 report<ErrorCode15>();
116 break;
117 case ErrorCode::_16:
118 report<ErrorCode16>();
119 break;
120 case ErrorCode::_17:
121 report<ErrorCode17>();
122 break;
123 case ErrorCode::_18:
124 report<ErrorCode18>();
125 break;
126 case ErrorCode::_19:
127 report<ErrorCode19>();
128 break;
129 case ErrorCode::_20:
130 report<ErrorCode20>();
131 break;
132 case ErrorCode::_21:
133 report<ErrorCode21>();
134 break;
135 case ErrorCode::_22:
136 report<ErrorCode22>();
137 break;
138 case ErrorCode::_23:
139 report<ErrorCode23>();
140 break;
141 case ErrorCode::_24:
142 report<ErrorCode24>();
143 break;
144 case ErrorCode::_25:
145 report<ErrorCode25>();
146 break;
147 case ErrorCode::_26:
148 report<ErrorCode26>();
149 break;
150 case ErrorCode::_27:
151 report<ErrorCode27>();
152 break;
153 case ErrorCode::_28:
154 report<ErrorCode28>();
155 break;
156 case ErrorCode::_29:
157 report<ErrorCode29>();
158 break;
159 case ErrorCode::_30:
160 report<ErrorCode30>();
161 break;
162 case ErrorCode::_31:
163 report<ErrorCode31>();
164 break;
165 case ErrorCode::_32:
166 report<ErrorCode32>();
167 break;
168 case ErrorCode::_33:
169 report<ErrorCode33>();
170 break;
171 case ErrorCode::_34:
172 report<ErrorCode34>();
173 break;
174 case ErrorCode::_35:
175 report<ErrorCode35>();
176 break;
177 case ErrorCode::_36:
178 report<ErrorCode36>();
179 break;
180 default:
181 // If the errorcode isn't 1~36,
182 // it indicates that the CPLD register
183 // has a reading issue,
184 // so the errorcode0 error is reported.
185 report<ErrorCode0>();
186 break;
187 }
188 clearCPLDregister();
189 }
190 }
191
analyze()192 void MihawkCPLD::analyze()
193 {
194 bool powerreadyError = checkPowerreadyFault();
195
196 // Use the function of GPIO class to check
197 // GPIOF0(CPLD uses).
198 using namespace phosphor::gpio;
199 GPIO gpio{"/dev/gpiochip0", static_cast<gpioNum_t>(40), Direction::input};
200
201 // Check GPIOFO pin whether is switched off.
202 // if GPIOF0 has been switched off,
203 // check CPLD's errorcode & report error.
204 if (gpio.read() == Value::low)
205 {
206 // If the interrupt of power_ready_error is switch on,
207 // read CPLD_register error code to analyze and
208 // report the error event.
209 if (powerreadyError)
210 {
211 ErrorCode code;
212 code = static_cast<ErrorCode>(readFromCPLDErrorCode(StatusReg_3));
213
214 if (!errorcodeMask)
215 {
216 // Check the errorcodeMask & errorcode whether
217 // are the same value to avoid to report the
218 // same error again.
219 switch (code)
220 {
221 case ErrorCode::_1:
222 report<ErrorCode1>();
223 errorcodeMask = 1;
224 break;
225 case ErrorCode::_2:
226 report<ErrorCode2>();
227 errorcodeMask = 1;
228 break;
229 case ErrorCode::_3:
230 report<ErrorCode3>();
231 errorcodeMask = 1;
232 break;
233 case ErrorCode::_4:
234 report<ErrorCode4>();
235 errorcodeMask = 1;
236 break;
237 case ErrorCode::_5:
238 report<ErrorCode5>();
239 errorcodeMask = 1;
240 break;
241 case ErrorCode::_6:
242 report<ErrorCode6>();
243 errorcodeMask = 1;
244 break;
245 case ErrorCode::_7:
246 report<ErrorCode7>();
247 errorcodeMask = 1;
248 break;
249 case ErrorCode::_8:
250 report<ErrorCode8>();
251 errorcodeMask = 1;
252 break;
253 case ErrorCode::_9:
254 report<ErrorCode9>();
255 errorcodeMask = 1;
256 break;
257 case ErrorCode::_10:
258 report<ErrorCode10>();
259 errorcodeMask = 1;
260 break;
261 case ErrorCode::_11:
262 report<ErrorCode11>();
263 errorcodeMask = 1;
264 break;
265 case ErrorCode::_12:
266 report<ErrorCode12>();
267 errorcodeMask = 1;
268 break;
269 case ErrorCode::_13:
270 report<ErrorCode13>();
271 errorcodeMask = 1;
272 break;
273 case ErrorCode::_14:
274 report<ErrorCode14>();
275 errorcodeMask = 1;
276 break;
277 case ErrorCode::_15:
278 report<ErrorCode15>();
279 errorcodeMask = 1;
280 break;
281 case ErrorCode::_16:
282 report<ErrorCode16>();
283 errorcodeMask = 1;
284 break;
285 case ErrorCode::_17:
286 report<ErrorCode17>();
287 errorcodeMask = 1;
288 break;
289 case ErrorCode::_18:
290 report<ErrorCode18>();
291 errorcodeMask = 1;
292 break;
293 case ErrorCode::_19:
294 report<ErrorCode19>();
295 errorcodeMask = 1;
296 break;
297 case ErrorCode::_20:
298 report<ErrorCode20>();
299 errorcodeMask = 1;
300 break;
301 case ErrorCode::_21:
302 report<ErrorCode21>();
303 errorcodeMask = 1;
304 break;
305 case ErrorCode::_22:
306 report<ErrorCode22>();
307 errorcodeMask = 1;
308 break;
309 case ErrorCode::_23:
310 report<ErrorCode23>();
311 errorcodeMask = 1;
312 break;
313 case ErrorCode::_24:
314 report<ErrorCode24>();
315 errorcodeMask = 1;
316 break;
317 case ErrorCode::_25:
318 report<ErrorCode25>();
319 errorcodeMask = 1;
320 break;
321 case ErrorCode::_26:
322 report<ErrorCode26>();
323 errorcodeMask = 1;
324 break;
325 case ErrorCode::_27:
326 report<ErrorCode27>();
327 errorcodeMask = 1;
328 break;
329 case ErrorCode::_28:
330 report<ErrorCode28>();
331 errorcodeMask = 1;
332 break;
333 case ErrorCode::_29:
334 report<ErrorCode29>();
335 errorcodeMask = 1;
336 break;
337 case ErrorCode::_30:
338 report<ErrorCode30>();
339 errorcodeMask = 1;
340 break;
341 case ErrorCode::_31:
342 report<ErrorCode31>();
343 errorcodeMask = 1;
344 break;
345 case ErrorCode::_32:
346 report<ErrorCode32>();
347 errorcodeMask = 1;
348 break;
349 case ErrorCode::_33:
350 report<ErrorCode33>();
351 errorcodeMask = 1;
352 break;
353 case ErrorCode::_34:
354 report<ErrorCode34>();
355 errorcodeMask = 1;
356 break;
357 case ErrorCode::_35:
358 report<ErrorCode35>();
359 errorcodeMask = 1;
360 break;
361 case ErrorCode::_36:
362 report<ErrorCode36>();
363 errorcodeMask = 1;
364 break;
365 default:
366 // If the errorcode is not 1~36,
367 // it indicates that the CPLD register
368 // has a reading issue, so the
369 // errorcode0 error is reported.
370 report<ErrorCode0>();
371 errorcodeMask = 1;
372 break;
373 }
374 }
375 clearCPLDregister();
376 }
377 }
378
379 if (gpio.read() == Value::high)
380 {
381 // If there isn't an error(GPIOF0
382 // which CPLD uses is switched on),
383 // we clear errorcodeMask.
384 errorcodeMask = 0;
385 }
386 }
387
388 // Check for PoweronFault
checkPoweronFault()389 bool MihawkCPLD::checkPoweronFault()
390 {
391 uint16_t statusValue_1;
392 bool result;
393
394 if (!i2c)
395 {
396 openCPLDDevice();
397 }
398 i2c->read(StatusReg_1, statusValue_1);
399
400 if (statusValue_1 < 0)
401 {
402 std::cerr << "i2c->read() reads data failed \n";
403 result = 0;
404 }
405
406 if ((statusValue_1 >> 5) & 1)
407 {
408 // If power_on-interrupt-bit is read as 1,
409 // switch on the flag.
410 result = 1;
411 }
412 else
413 {
414 result = 0;
415 }
416
417 // Return the flag.
418 return result;
419 }
420
421 // Read CPLD_register error code and return the result to analyze.
readFromCPLDErrorCode(int statusReg)422 int MihawkCPLD::readFromCPLDErrorCode(int statusReg)
423 {
424 uint16_t statusValue_2;
425
426 if (!i2c)
427 {
428 openCPLDDevice();
429 }
430 i2c->read(statusReg, statusValue_2);
431
432 if (statusValue_2 < 0 ||
433 ((statusValue_2 > static_cast<int>(ErrorCode::_35)) &&
434 (statusValue_2 != static_cast<int>(ErrorCode::_36))))
435 {
436 statusValue_2 = 0;
437 }
438
439 // Return the data via i2c->read().
440 return statusValue_2;
441 }
442
443 // Check for PowerreadyFault
checkPowerreadyFault()444 bool MihawkCPLD::checkPowerreadyFault()
445 {
446 uint16_t statusValue_3;
447 bool result;
448
449 if (!i2c)
450 {
451 openCPLDDevice();
452 }
453 i2c->read(StatusReg_1, statusValue_3);
454
455 if (statusValue_3 < 0)
456 {
457 std::cerr << "i2c->read() reads data failed \n";
458 result = 0;
459 }
460
461 if ((statusValue_3 >> 6) & 1)
462 {
463 // If power_ready-interrupt-bit is read as 1,
464 // switch on the flag.
465 result = 1;
466 }
467 else
468 {
469 result = 0;
470 }
471
472 // Return the flag.
473 return result;
474 }
475
476 // Clear CPLD_register after reading.
clearCPLDregister()477 void MihawkCPLD::clearCPLDregister()
478 {
479 uint16_t data = 0x01;
480 uint16_t checkpsu;
481
482 if (!i2c)
483 {
484 openCPLDDevice();
485 }
486
487 // check psu pgood status.
488 i2c->read(StatusReg_0, checkpsu);
489
490 // check one of both psus pgood status before
491 // clear CPLD_register.
492 if (((checkpsu >> 1) & 1) || ((checkpsu >> 2) & 1))
493 {
494 // Write 0x01 to StatusReg_1 for clearing
495 // CPLD_register.
496 i2c->write(StatusReg_1, data);
497 }
498 }
499
500 // Open i2c device(CPLD_register)
openCPLDDevice()501 void MihawkCPLD::openCPLDDevice()
502 {
503 i2c = i2c::create(busId, slaveAddr);
504 }
505
506 } // namespace power
507 } // namespace phosphor
508