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