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 54 MihawkCPLD::MihawkCPLD(size_t instance, sdbusplus::bus::bus& bus) : 55 Device(DEVICE_NAME, instance), bus(bus) 56 {} 57 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 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 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. 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 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. 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) 501 void MihawkCPLD::openCPLDDevice() 502 { 503 i2c = i2c::create(busId, slaveAddr); 504 } 505 506 } // namespace power 507 } // namespace phosphor 508