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