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 59 void 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 193 void 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 } 375 } 376 clearCPLDregister(); 377 } 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 390 bool 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. 423 int 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 445 bool 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. 478 void MihawkCPLD::clearCPLDregister() 479 { 480 uint16_t data = 0x01; 481 uint16_t checkpsu; 482 483 if (!i2c) 484 { 485 openCPLDDevice(); 486 } 487 488 // 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 } 499 } 500 501 // Open i2c device(CPLD_register) 502 void MihawkCPLD::openCPLDDevice() 503 { 504 i2c = i2c::create(busId, slaveAddr); 505 } 506 507 } // namespace power 508 } // namespace phosphor 509