diff options
Diffstat (limited to 'cvmx-error-custom.c')
-rw-r--r-- | cvmx-error-custom.c | 297 |
1 files changed, 281 insertions, 16 deletions
diff --git a/cvmx-error-custom.c b/cvmx-error-custom.c index 3aeaa0df089d..64768a6a79e1 100644 --- a/cvmx-error-custom.c +++ b/cvmx-error-custom.c @@ -1,5 +1,5 @@ /***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights * reserved. * * @@ -15,7 +15,7 @@ * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Cavium Networks nor the names of + * * Neither the name of Cavium Inc. nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -26,7 +26,7 @@ * countries. * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM @@ -58,6 +58,7 @@ #include <asm/octeon/cvmx-gmxx-defs.h> #include <asm/octeon/cvmx-lmcx-defs.h> #include <asm/octeon/cvmx-pemx-defs.h> +#include <asm/octeon/cvmx-sriox-defs.h> #define PRINT_ERROR(format, ...) cvmx_safe_printf("ERROR " format, ##__VA_ARGS__) #else #include "cvmx.h" @@ -82,6 +83,21 @@ static int __cvmx_error_handle_gmxx_rxx_int_reg(const struct cvmx_error_info *in { #ifdef CVMX_ENABLE_PKO_FUNCTIONS int ipd_port = info->group_index; + switch(ipd_port) + { + case 0x800: + ipd_port = 0x840; + break; + case 0xa00: + ipd_port = 0xa40; + break; + case 0xb00: + ipd_port = 0xb40; + break; + case 0xc00: + ipd_port = 0xc40; + break; + } cvmx_helper_link_autoconf(ipd_port); #endif cvmx_write_csr(info->status_addr, info->status_mask); @@ -140,6 +156,136 @@ static int __cvmx_error_handle_npei_int_sum_c1_ldwn(const struct cvmx_error_info return 1; } +#define DECODE_FAILING_ADDRESS +//#define DECODE_FAILING_BIT + +#ifdef DECODE_FAILING_BIT +#define _Db(x) (x) /* Data Bit */ +#define _Ec(x) (0x100+x) /* ECC Bit */ +#define _Ad(x) (0x200+x) /* Address Bit */ +#define _Bu(x) (0x400+x) /* Burst */ +#define _Un() (-1) /* Unused */ +/* Use ECC Code as index to lookup corrected bit */ +const static short lmc_syndrome_bits[256] = { + /* __ 0 __ __ 1 __ __ 2 __ __ 3 __ __ 4 __ __ 5 __ __ 6 __ __ 7 __ __ 8 __ __ 9 __ __ A __ __ B __ __ C __ __ D __ __ E __ __ F __ */ + /* 00: */ _Un( ), _Ec( 0), _Ec( 1), _Un( ), _Ec( 2), _Un( ), _Un( ), _Un( ), _Ec( 3), _Un( ), _Un( ), _Db(17), _Un( ), _Un( ), _Db(16), _Un( ), + /* 10: */ _Ec( 4), _Un( ), _Un( ), _Db(18), _Un( ), _Db(19), _Db(20), _Un( ), _Un( ), _Db(21), _Db(22), _Un( ), _Db(23), _Un( ), _Un( ), _Un( ), + /* 20: */ _Ec( 5), _Un( ), _Un( ), _Db( 8), _Un( ), _Db( 9), _Db(10), _Un( ), _Un( ), _Db(11), _Db(12), _Un( ), _Db(13), _Un( ), _Un( ), _Un( ), + /* 30: */ _Un( ), _Db(14), _Un( ), _Un( ), _Db(15), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Ad(34), _Un( ), + /* 40: */ _Ec( 6), _Un( ), _Un( ), _Un( ), _Un( ), _Ad( 7), _Ad( 8), _Un( ), _Un( ), _Ad( 9), _Db(33), _Un( ), _Ad(10), _Un( ), _Un( ), _Db(32), + /* 50: */ _Un( ), _Ad(11), _Db(34), _Un( ), _Db(35), _Un( ), _Un( ), _Db(36), _Db(37), _Un( ), _Un( ), _Db(38), _Un( ), _Db(39), _Ad(12), _Un( ), + /* 60: */ _Un( ), _Ad(13), _Db(56), _Un( ), _Db(57), _Un( ), _Un( ), _Db(58), _Db(59), _Un( ), _Un( ), _Db(60), _Un( ), _Db(61), _Ad(14), _Un( ), + /* 70: */ _Db(62), _Un( ), _Un( ), _Ad(15), _Un( ), _Db(63), _Ad(16), _Un( ), _Un( ), _Ad(17), _Ad(18), _Un( ), _Ad(19), _Un( ), _Ad(20), _Un( ), + /* 80: */ _Ec( 7), _Un( ), _Un( ), _Ad(21), _Un( ), _Ad(22), _Ad(23), _Un( ), _Un( ), _Ad(24), _Db(49), _Un( ), _Ad(25), _Un( ), _Un( ), _Db(48), + /* 90: */ _Un( ), _Ad(26), _Db(50), _Un( ), _Db(51), _Un( ), _Un( ), _Db(52), _Db(53), _Un( ), _Un( ), _Db(54), _Un( ), _Db(55), _Ad(27), _Un( ), + /* A0: */ _Un( ), _Ad(28), _Db(40), _Un( ), _Db(41), _Un( ), _Un( ), _Db(42), _Db(43), _Un( ), _Un( ), _Db(44), _Un( ), _Db(45), _Ad(29), _Un( ), + /* B0: */ _Db(46), _Un( ), _Un( ), _Ad(30), _Un( ), _Db(47), _Ad(31), _Un( ), _Un( ), _Ad(32), _Ad(33), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), + /* C0: */ _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Db( 1), _Un( ), _Un( ), _Db( 0), _Un( ), + /* D0: */ _Un( ), _Un( ), _Un( ), _Db( 2), _Un( ), _Db( 3), _Db( 4), _Un( ), _Un( ), _Db( 5), _Db( 6), _Un( ), _Db( 7), _Un( ), _Un( ), _Un( ), + /* E0: */ _Un( ), _Un( ), _Un( ), _Db(24), _Un( ), _Db(25), _Db(26), _Un( ), _Un( ), _Db(27), _Db(28), _Un( ), _Db(29), _Un( ), _Un( ), _Un( ), + /* F0: */ _Un( ), _Db(30), _Un( ), _Un( ), _Db(31), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ), _Un( ) +}; +#endif + +/** + * @INTERNAL + * This error bit handler clears the status and prints failure infomation. + * + * @param info Error register to check + * + * @return + */ +static int __cvmx_cn6xxx_lmc_ecc_error_display(const cvmx_error_info_t *info) +{ +#ifdef DECODE_FAILING_ADDRESS + cvmx_lmcx_config_t lmc_config; + uint64_t fadr_physical, fadr_data; +#endif + + int ddr_controller = info->group_index; + cvmx_lmcx_int_t lmc_int; + cvmx_lmcx_fadr_t fadr; + cvmx_lmcx_ecc_synd_t ecc_synd; + int sec_err; + int ded_err; + int syndrome = -1; + int phase; + + lmc_int.u64 = cvmx_read_csr(CVMX_LMCX_INT(ddr_controller)); + fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(ddr_controller)); + ecc_synd.u64 = cvmx_read_csr(CVMX_LMCX_ECC_SYND(ddr_controller)); + /* This assumes that all bits in the status register are RO or R/W1C */ + cvmx_write_csr(info->status_addr, info->status_mask); + +#ifdef DECODE_FAILING_ADDRESS + lmc_config.u64 = cvmx_read_csr(CVMX_LMCX_CONFIG(ddr_controller)); +#endif + + sec_err = lmc_int.s.sec_err; + ded_err = lmc_int.s.ded_err; + + phase = ded_err ? ded_err : sec_err; /* Double bit errors take precedence. */ + + switch (phase) { + case 1: + syndrome = ecc_synd.cn63xx.mrdsyn0; + break; + case 2: + syndrome = ecc_synd.cn63xx.mrdsyn1; + break; + case 4: + syndrome = ecc_synd.cn63xx.mrdsyn2; + break; + case 8: + syndrome = ecc_synd.cn63xx.mrdsyn3; + break; + } + +#ifdef DECODE_FAILING_ADDRESS + fadr_physical = (uint64_t)fadr.cn63xx.fdimm << (lmc_config.s.pbank_lsb + 28); + fadr_physical |= (uint64_t)fadr.cn63xx.frow << (lmc_config.s.row_lsb + 14); + fadr_physical |= (uint64_t)fadr.cn63xx.fbank << 7; + fadr_physical |= (uint64_t)(fadr.cn63xx.fcol&0xf) << 3; + fadr_physical |= (uint64_t)(fadr.cn63xx.fcol>>4) << 10; + + fadr_data = *(uint64_t*)cvmx_phys_to_ptr(fadr_physical); +#endif + + PRINT_ERROR("LMC%d ECC: sec_err:%d ded_err:%d\n" + "LMC%d ECC:\tFailing dimm: %u\n" + "LMC%d ECC:\tFailing rank: %u\n" + "LMC%d ECC:\tFailing bank: %u\n" + "LMC%d ECC:\tFailing row: 0x%x\n" + "LMC%d ECC:\tFailing column: 0x%x\n" + "LMC%d ECC:\tsyndrome: 0x%x" +#ifdef DECODE_FAILING_BIT + ", bit: %d" +#endif + "\n" +#ifdef DECODE_FAILING_ADDRESS + "Failing Address: 0x%016llx, Data: 0x%016llx\n" +#endif + , /* Comma */ + ddr_controller, sec_err, ded_err, + ddr_controller, fadr.cn63xx.fdimm, + ddr_controller, fadr.cn63xx.fbunk, + ddr_controller, fadr.cn63xx.fbank, + ddr_controller, fadr.cn63xx.frow, + ddr_controller, fadr.cn63xx.fcol, + ddr_controller, syndrome +#ifdef DECODE_FAILING_BIT + , /* Comma */ + lmc_syndrome_bits[syndrome] +#endif +#ifdef DECODE_FAILING_ADDRESS + , /* Comma */ + (unsigned long long) fadr_physical, (unsigned long long) fadr_data +#endif + ); + + return 1; +} + /** * @INTERNAL * Some errors require more complicated error handing functions than the @@ -150,25 +296,60 @@ static int __cvmx_error_handle_npei_int_sum_c1_ldwn(const struct cvmx_error_info */ int __cvmx_error_custom_initialize(void) { - if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) + if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) { - cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, - CVMX_GMXX_RXX_INT_REG(0,0), 1ull<<21 /* rem_fault */, - __cvmx_error_handle_gmxx_rxx_int_reg, 0, NULL, NULL); - cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, - CVMX_GMXX_RXX_INT_REG(0,0), 1ull<<20 /* loc_fault */, - __cvmx_error_handle_gmxx_rxx_int_reg, 0, NULL, NULL); + int lmc; + for (lmc = 0; lmc < CVMX_L2C_TADS; lmc++) + { + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + { + cvmx_lmcx_dll_ctl2_t ctl; + ctl.u64 = cvmx_read_csr(CVMX_LMCX_DLL_CTL2(lmc)); + if (ctl.s.intf_en == 0) + continue; + } + cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, + CVMX_LMCX_INT(lmc), 0xfull<<1 /* sec_err */, + __cvmx_cn6xxx_lmc_ecc_error_display, 0, NULL, NULL); + cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, + CVMX_LMCX_INT(lmc), 0xfull<<5 /* ded_err */, + __cvmx_cn6xxx_lmc_ecc_error_display, 0, NULL, NULL); + if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) + { + int i; + + for (i = 0; i < 6; i++) + cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, + CVMX_L2C_TADX_INT(lmc), (1ull << i), + __cvmx_error_handle_63XX_l2_ecc, 0, NULL, NULL); + } + } } - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) + if (OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX) + || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) { - cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, - CVMX_GMXX_RXX_INT_REG(0,1), 1ull<<21 /* rem_fault */, + int i; + + /* Install special handler for all the interfaces, these are + specific to XAUI interface */ + for (i = 0; i < CVMX_HELPER_MAX_GMX; i++) + { + if ((OCTEON_IS_MODEL(OCTEON_CN63XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CNF71XX)) + && i == 1) + continue; + cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, + CVMX_GMXX_RXX_INT_REG(0,i), 1ull<<21 /* rem_fault */, __cvmx_error_handle_gmxx_rxx_int_reg, 0, NULL, NULL); - cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, - CVMX_GMXX_RXX_INT_REG(0,1), 1ull<<20 /* loc_fault */, + cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, + CVMX_GMXX_RXX_INT_REG(0,i), 1ull<<20 /* loc_fault */, __cvmx_error_handle_gmxx_rxx_int_reg, 0, NULL, NULL); + } } - if (octeon_has_feature(OCTEON_FEATURE_NPEI)) + if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { cvmx_error_change_handler(CVMX_ERROR_REGISTER_IO64, CVMX_PEXP_NPEI_INT_SUM, 1ull<<59 /* c0_ldwn */, @@ -191,6 +372,14 @@ int __cvmx_error_custom_initialize(void) cvmx_error_disable(CVMX_ERROR_REGISTER_IO64, CVMX_PEMX_INT_SUM(1), 1ull<<13); } + /* According to the workaround for errata SRIO-15282, clearing + SRIOx_INT_ENABLE[MAC_BUF]. */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) && OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)) + { + cvmx_error_disable(CVMX_ERROR_REGISTER_IO64, CVMX_SRIOX_INT_ENABLE(0), 1ull<<22); + cvmx_error_disable(CVMX_ERROR_REGISTER_IO64, CVMX_SRIOX_INT_ENABLE(1), 1ull<<22); + } + return 0; } @@ -622,3 +811,79 @@ int __cvmx_error_handle_pow_ecc_err_sbe(const struct cvmx_error_info *info) } +/** + * @INTERNAL + * + * @param info + * + * @return + */ +int __cvmx_error_handle_63XX_l2_ecc(const struct cvmx_error_info *info) +{ + cvmx_l2c_err_tdtx_t l2c_err_tdt; + cvmx_l2c_err_ttgx_t l2c_err_ttg; + cvmx_l2c_err_vbfx_t l2c_err_vbf; + cvmx_l2c_tadx_int_t tadx_int; + tadx_int.u64 = cvmx_read_csr(CVMX_L2C_TADX_INT(0)); + l2c_err_tdt.u64 = cvmx_read_csr(CVMX_L2C_ERR_TDTX(0)); + l2c_err_ttg.u64 = cvmx_read_csr(CVMX_L2C_ERR_TTGX(0)); + l2c_err_vbf.u64 = cvmx_read_csr(CVMX_L2C_ERR_VBFX(0)); + cvmx_write_csr(CVMX_L2C_TADX_INT(0), tadx_int.u64); + + if (tadx_int.cn63xx.l2ddbe || tadx_int.cn63xx.l2dsbe) + { + /* L2 Data error */ + + + if (tadx_int.cn63xx.l2dsbe) + { + /* l2c_err_tdt.cn63xx.wayidx formated same as CACHE instruction arg */ + CVMX_CACHE_WBIL2I((l2c_err_tdt.u64 & 0x1fff80) | (1ULL << 63), 0); + CVMX_SYNC; + PRINT_ERROR("L2C_TADX_INT(0)[L2DSBE]: Data Single-Bit Error\n"); + } + if (tadx_int.cn63xx.l2ddbe) + { + /* TODO - fatal error, for now, flush so error cleared..... */ + CVMX_CACHE_WBIL2I((l2c_err_tdt.u64 & 0x1fff80) | (1ULL << 63), 0); + CVMX_SYNC; + PRINT_ERROR("L2C_TADX_INT(0)[L2DDBE]: Data Double-Bit Error\n"); + } + PRINT_ERROR("CVMX_L2C_ERR_TDT: 0x%llx\n", (unsigned long long)l2c_err_tdt.u64); + } + if (tadx_int.cn63xx.tagdbe || tadx_int.cn63xx.tagsbe) + { + /* L2 Tag error */ + if (tadx_int.cn63xx.tagsbe) + { + CVMX_CACHE_WBIL2I((l2c_err_ttg.u64 & 0x1fff80) | (1ULL << 63), 0); + CVMX_SYNC; + PRINT_ERROR("L2C_TADX_INT(0)[TAGSBE]: Tag Single-Bit Error\n"); + } + if (tadx_int.cn63xx.tagdbe) + { + /* TODO - fatal error, for now, flush so error cleared..... */ + CVMX_CACHE_WBIL2I((l2c_err_ttg.u64 & 0x1fff80) | (1ULL << 63), 0); + CVMX_SYNC; + PRINT_ERROR("L2C_TADX_INT(0)[TAGDBE]: Tag Double-Bit Error\n"); + } + PRINT_ERROR("CVMX_L2C_ERR_TTG: 0x%llx\n", (unsigned long long)l2c_err_ttg.u64); + } + if (tadx_int.cn63xx.vbfdbe || tadx_int.cn63xx.vbfsbe) + { + /* L2 Victim buffer error */ + if (tadx_int.cn63xx.vbfsbe) + { + /* No action here, hardware fixed up on write to DRAM */ + PRINT_ERROR("L2C_TADX_INT(0)[VBFSBE]: VBF Single-Bit Error\n"); + } + if (tadx_int.cn63xx.vbfdbe) + { + /* TODO - fatal error. Bad data written to DRAM. */ + PRINT_ERROR("L2C_TADX_INT(0)[VBFDBE]: VBF Double-Bit Error\n"); + } + PRINT_ERROR("CVMX_L2C_ERR_VBF: 0x%llx\n", (unsigned long long)l2c_err_vbf.u64); + } + + return 1; +} |