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