/* * SPDX-FileCopyrightText: Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "common_nvswitch.h" #include "intr_nvswitch.h" #include "regkey_nvswitch.h" #include "soe/soe_nvswitch.h" #include "ls10/ls10.h" #include "ls10/minion_ls10.h" #include "ls10/soe_ls10.h" #include "nvswitch/ls10/dev_ctrl_ip.h" #include "nvswitch/ls10/dev_pri_masterstation_ip.h" #include "nvswitch/ls10/dev_pri_hub_sys_ip.h" #include "nvswitch/ls10/dev_pri_hub_sysb_ip.h" #include "nvswitch/ls10/dev_pri_hub_prt_ip.h" #include "nvswitch/ls10/dev_npg_ip.h" #include "nvswitch/ls10/dev_nport_ip.h" #include "nvswitch/ls10/dev_route_ip.h" #include "nvswitch/ls10/dev_ingress_ip.h" #include "nvswitch/ls10/dev_sourcetrack_ip.h" #include "nvswitch/ls10/dev_egress_ip.h" #include "nvswitch/ls10/dev_tstate_ip.h" #include "nvswitch/ls10/dev_multicasttstate_ip.h" #include "nvswitch/ls10/dev_reductiontstate_ip.h" #include "nvswitch/ls10/dev_nvlw_ip.h" #include "nvswitch/ls10/dev_minion_ip.h" #include "nvswitch/ls10/dev_minion_ip_addendum.h" #include "nvswitch/ls10/dev_cpr_ip.h" #include "nvswitch/ls10/dev_nvlipt_ip.h" #include "nvswitch/ls10/dev_nvlipt_lnk_ip.h" #include "nvswitch/ls10/dev_nvltlc_ip.h" #include "nvswitch/ls10/dev_nvldl_ip.h" #include "nvswitch/ls10/dev_nxbar_tcp_global_ip.h" #include "nvswitch/ls10/dev_nxbar_tile_ip.h" #include "nvswitch/ls10/dev_nxbar_tileout_ip.h" #include "nvswitch/ls10/dev_ctrl_ip_addendum.h" static void _nvswitch_create_deferred_link_errors_task_ls10(nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link); static void _nvswitch_construct_ecc_error_event_ls10 ( INFOROM_NVS_ECC_ERROR_EVENT *err_event, NvU32 sxid, NvU32 linkId, NvBool bAddressValid, NvU32 address, NvBool bUncErr, NvU32 errorCount ) { err_event->sxid = sxid; err_event->linkId = linkId; err_event->bAddressValid = bAddressValid; err_event->address = address; err_event->bUncErr = bUncErr; err_event->errorCount = errorCount; } static void _nvswitch_initialize_minion_interrupts ( nvswitch_device *device, NvU32 instance ) { NvU32 intrEn, localDiscoveredLinks, globalLink, i; localDiscoveredLinks = 0; // Tree 1 (non-stall) is disabled until there is a need NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _MINION_INTR_NONSTALL_EN, 0); // Tree 0 (stall) is where we route _all_ MINION interrupts for now intrEn = DRF_DEF(_MINION, _MINION_INTR_STALL_EN, _FATAL, _ENABLE) | DRF_DEF(_MINION, _MINION_INTR_STALL_EN, _NONFATAL, _ENABLE) | DRF_DEF(_MINION, _MINION_INTR_STALL_EN, _FALCON_STALL, _ENABLE) | DRF_DEF(_MINION, _MINION_INTR_STALL_EN, _FALCON_NOSTALL, _DISABLE); for (i = 0; i < NVSWITCH_LINKS_PER_MINION_LS10; ++i) { // get the global link number of the link we are iterating over globalLink = (instance * NVSWITCH_LINKS_PER_MINION_LS10) + i; // the link is valid place bit in link mask if (device->link[globalLink].valid) { localDiscoveredLinks |= NVBIT(i); } } intrEn = FLD_SET_DRF_NUM(_MINION, _MINION_INTR_STALL_EN, _LINK, localDiscoveredLinks, intrEn); { // Disable interrupts only if explicitly requested to. Default to enable. if (device->regkeys.minion_intr != NV_SWITCH_REGKEY_MINION_INTERRUPTS_DISABLE) { NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _MINION_INTR_STALL_EN, intrEn); } } } static void _nvswitch_initialize_nvlipt_interrupts_ls10 ( nvswitch_device *device ) { NvU32 i; NvU32 regval = 0; // // NVLipt interrupt routing (NVLIPT_COMMON, NVLIPT_LNK, NVLDL, NVLTLC) // will be initialized by MINION NVLPROD flow // // We must enable interrupts at the top levels in NVLW, NVLIPT_COMMON, // NVLIPT_LNK and MINION // // NVLW regval = DRF_NUM(_NVLW_COMMON, _INTR_0_MASK, _FATAL, 0x1) | DRF_NUM(_NVLW_COMMON, _INTR_0_MASK, _NONFATAL, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_0_MASK, _CORRECTABLE, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_0_MASK, _INTR0, 0x1) | DRF_NUM(_NVLW_COMMON, _INTR_0_MASK, _INTR1, 0x0); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_COMMON, _INTR_0_MASK, regval); regval = DRF_NUM(_NVLW_COMMON, _INTR_1_MASK, _FATAL, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_1_MASK, _NONFATAL, 0x1) | DRF_NUM(_NVLW_COMMON, _INTR_1_MASK, _CORRECTABLE, 0x1) | DRF_NUM(_NVLW_COMMON, _INTR_1_MASK, _INTR0, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_1_MASK, _INTR1, 0x1); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_COMMON, _INTR_1_MASK, regval); regval = DRF_NUM(_NVLW_COMMON, _INTR_2_MASK, _FATAL, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_2_MASK, _NONFATAL, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_2_MASK, _CORRECTABLE, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_2_MASK, _INTR0, 0x0) | DRF_NUM(_NVLW_COMMON, _INTR_2_MASK, _INTR1, 0x0); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_COMMON, _INTR_2_MASK, regval); // NVLW link for (i = 0; i < NV_NVLW_LINK_INTR_0_MASK__SIZE_1; i++) { regval = DRF_NUM(_NVLW_LINK, _INTR_0_MASK, _FATAL, 0x1) | DRF_NUM(_NVLW_LINK, _INTR_0_MASK, _NONFATAL, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_0_MASK, _CORRECTABLE, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_0_MASK, _INTR0, 0x1) | DRF_NUM(_NVLW_LINK, _INTR_0_MASK, _INTR1, 0x0); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_LINK, _INTR_0_MASK(i), regval); regval = DRF_NUM(_NVLW_LINK, _INTR_1_MASK, _FATAL, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_1_MASK, _NONFATAL, 0x1) | DRF_NUM(_NVLW_LINK, _INTR_1_MASK, _CORRECTABLE, 0x1) | DRF_NUM(_NVLW_LINK, _INTR_1_MASK, _INTR0, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_1_MASK, _INTR1, 0x1); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_LINK, _INTR_1_MASK(i), regval); regval = DRF_NUM(_NVLW_LINK, _INTR_2_MASK, _FATAL, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_2_MASK, _NONFATAL, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_2_MASK, _CORRECTABLE, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_2_MASK, _INTR0, 0x0) | DRF_NUM(_NVLW_LINK, _INTR_2_MASK, _INTR1, 0x0); NVSWITCH_BCAST_WR32_LS10(device, NVLW, _NVLW_LINK, _INTR_2_MASK(i), regval); } // NVLIPT_COMMON regval = DRF_NUM(_NVLIPT_COMMON, _INTR_CONTROL_COMMON, _INT0_EN, 0x1) | DRF_NUM(_NVLIPT_COMMON, _INTR_CONTROL_COMMON, _INT1_EN, 0x1); NVSWITCH_BCAST_WR32_LS10(device, NVLIPT, _NVLIPT_COMMON, _INTR_CONTROL_COMMON, regval); // NVLIPT_LNK regval = DRF_NUM(_NVLIPT_LNK, _INTR_CONTROL_LINK, _INT0_EN, 0x1) | DRF_NUM(_NVLIPT_LNK, _INTR_CONTROL_LINK, _INT1_EN, 0x1); NVSWITCH_BCAST_WR32_LS10(device, NVLIPT_LNK, _NVLIPT_LNK, _INTR_CONTROL_LINK, regval); // NVLIPT_LNK_INTR_1 regval = DRF_NUM(_NVLIPT_LNK, _INTR_INT1_EN, _LINKSTATEREQUESTREADYSET, 0x1); NVSWITCH_BCAST_WR32_LS10(device, NVLIPT_LNK, _NVLIPT_LNK, _INTR_INT1_EN, regval); // MINION for (i = 0; i < NUM_MINION_ENGINE_LS10; ++i) { if (!NVSWITCH_ENG_VALID_LS10(device, MINION, i)) { continue; } _nvswitch_initialize_minion_interrupts(device,i); } // CPR regval = NVSWITCH_ENG_RD32(device, CPR, _BCAST, 0, _CPR_SYS, _ERR_LOG_EN_0); regval = FLD_SET_DRF(_CPR_SYS, _ERR_LOG_EN_0, _ENGINE_RESET_ERR, __PROD, regval); NVSWITCH_ENG_WR32(device, CPR, _BCAST, 0, _CPR_SYS, _ERR_LOG_EN_0, regval); regval = DRF_DEF(_CPR_SYS, _NVLW_INTR_0_MASK, _CPR_INTR, _ENABLE) | DRF_DEF(_CPR_SYS, _NVLW_INTR_0_MASK, _INTR0, _ENABLE); NVSWITCH_ENG_WR32(device, CPR, _BCAST, 0, _CPR_SYS, _NVLW_INTR_0_MASK, regval); regval = DRF_DEF(_CPR_SYS, _NVLW_INTR_1_MASK, _CPR_INTR, _DISABLE) | DRF_DEF(_CPR_SYS, _NVLW_INTR_1_MASK, _INTR1, _ENABLE); NVSWITCH_ENG_WR32(device, CPR, _BCAST, 0, _CPR_SYS, _NVLW_INTR_1_MASK, regval); regval = DRF_DEF(_CPR_SYS, _NVLW_INTR_2_MASK, _CPR_INTR, _DISABLE) | DRF_DEF(_CPR_SYS, _NVLW_INTR_2_MASK, _INTR2, _ENABLE); NVSWITCH_ENG_WR32(device, CPR, _BCAST, 0, _CPR_SYS, _NVLW_INTR_2_MASK, regval); } static void _nvswitch_initialize_route_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.route.fatal = DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _ROUTEBUFERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _GLT_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _PDCTRLPARERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _NVS_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _CDTPARERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _MCRID_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _EXTMCRID_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_FATAL_REPORT_EN_0, _RAM_ECC_DBE_ERR, _ENABLE); chip_device->intr_mask.route.nonfatal = DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _NOPORTDEFINEDERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _INVALIDROUTEPOLICYERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _GLT_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _NVS_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _MCRID_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _EXTMCRID_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _RAM_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_ROUTE, _ERR_NON_FATAL_REPORT_EN_0, _INVALID_MCRID_ERR, _ENABLE); // NOTE: _MC_TRIGGER_ERR is debug-use only } static void _nvswitch_initialize_ingress_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.ingress[0].fatal = DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _CMDDECODEERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _EXTAREMAPTAB_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _NCISOC_HDR_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _INVALIDVCSET, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _REMAPTAB_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _RIDTAB_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _RLANTAB_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _NCISOC_PARITY_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _EXTBREMAPTAB_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_FATAL_REPORT_EN_0, _MCREMAPTAB_ECC_DBE_ERR, _ENABLE); chip_device->intr_mask.ingress[0].nonfatal = DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _REQCONTEXTMISMATCHERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _ACLFAIL, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _NCISOC_HDR_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _ADDRBOUNDSERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RIDTABCFGERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RLANTABCFGERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _REMAPTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RIDTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RLANTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _ADDRTYPEERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTAREMAPTAB_INDEX_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTBREMAPTAB_INDEX_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _MCREMAPTAB_INDEX_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTAREMAPTAB_REQCONTEXTMISMATCHERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTBREMAPTAB_REQCONTEXTMISMATCHERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _MCREMAPTAB_REQCONTEXTMISMATCHERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTAREMAPTAB_ACLFAIL, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTBREMAPTAB_ACLFAIL, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _MCREMAPTAB_ACLFAIL, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTAREMAPTAB_ADDRBOUNDSERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _EXTBREMAPTAB_ADDRBOUNDSERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_0, _MCREMAPTAB_ADDRBOUNDSERR, _ENABLE); chip_device->intr_mask.ingress[1].fatal = 0; chip_device->intr_mask.ingress[1].nonfatal = DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _EXTAREMAPTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _EXTBREMAPTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCREMAPTAB_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCCMDTOUCADDRERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _READMCREFLECTMEMERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _EXTAREMAPTAB_ADDRTYPEERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _EXTBREMAPTAB_ADDRTYPEERR, _ENABLE) | DRF_DEF(_INGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCREMAPTAB_ADDRTYPEERR, _ENABLE); } static void _nvswitch_initialize_egress_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.egress[0].fatal = DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _EGRESSBUFERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _PKTROUTEERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _SEQIDERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NXBAR_HDR_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _RAM_OUT_HDR_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NCISOCCREDITOVFL, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _REQTGTIDMISMATCHERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _RSPREQIDMISMATCHERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NXBAR_HDR_PARITY_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NCISOC_CREDIT_PARITY_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NXBAR_FLITTYPE_MISMATCH_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _CREDIT_TIME_OUT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _INVALIDVCSET_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _NXBAR_SIDEBAND_PD_PARITY_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _URRSPERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_0, _HWRSPERR, _ENABLE); chip_device->intr_mask.egress[0].nonfatal = DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_0, _NXBAR_HDR_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RAM_OUT_HDR_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_0, _PRIVRSPERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_0, _RFU, _DISABLE); chip_device->intr_mask.egress[1].fatal = DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_1, _MCRSPCTRLSTORE_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_1, _RBCTRLSTORE_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_1, _MCREDSGT_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_FATAL_REPORT_EN_1, _MCRSP_RAM_HDR_ECC_DBE_ERR, _ENABLE); chip_device->intr_mask.egress[1].nonfatal = DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCRSPCTRLSTORE_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _RBCTRLSTORE_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCREDSGT_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCREDBUF_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCRSP_RAM_HDR_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _NXBAR_REDUCTION_HDR_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _NXBAR_REDUCTION_HDR_PARITY_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _NXBAR_REDUCTION_FLITTYPE_MISMATCH_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCREDBUF_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _MCRSP_CNT_ERR, _ENABLE) | DRF_DEF(_EGRESS, _ERR_NON_FATAL_REPORT_EN_1, _RBRSP_CNT_ERR, _ENABLE); } static void _nvswitch_initialize_tstate_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.tstate.fatal = DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _TAGPOOLBUFERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _TAGPOOL_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTOREBUFERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _ATO_ERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_FATAL_REPORT_EN_0, _CAMRSP_ERR, _ENABLE); chip_device->intr_mask.tstate.nonfatal = DRF_DEF(_TSTATE, _ERR_NON_FATAL_REPORT_EN_0, _TAGPOOL_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_TSTATE, _ERR_NON_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_LIMIT_ERR, _ENABLE); } static void _nvswitch_initialize_sourcetrack_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.sourcetrack.fatal = DRF_DEF(_SOURCETRACK, _ERR_FATAL_REPORT_EN_0, _CREQ_TCEN0_CRUMBSTORE_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_SOURCETRACK, _ERR_FATAL_REPORT_EN_0, _DUP_CREQ_TCEN0_TAG_ERR, _ENABLE) | DRF_DEF(_SOURCETRACK, _ERR_FATAL_REPORT_EN_0, _INVALID_TCEN0_RSP_ERR, _ENABLE) | DRF_DEF(_SOURCETRACK, _ERR_FATAL_REPORT_EN_0, _INVALID_TCEN1_RSP_ERR, _ENABLE) | DRF_DEF(_SOURCETRACK, _ERR_FATAL_REPORT_EN_0, _SOURCETRACK_TIME_OUT_ERR, _ENABLE); chip_device->intr_mask.sourcetrack.nonfatal = DRF_DEF(_SOURCETRACK, _ERR_NON_FATAL_REPORT_EN_0, _CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, _ENABLE); } static void _nvswitch_initialize_multicast_tstate_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.mc_tstate.fatal = DRF_DEF(_MULTICASTTSTATE, _ERR_FATAL_REPORT_EN_0, _TAGPOOL_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_MULTICASTTSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTORE_BUF_OVERWRITE_ERR, _ENABLE) | DRF_DEF(_MULTICASTTSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_DBE_ERR, _ENABLE); chip_device->intr_mask.mc_tstate.nonfatal = DRF_DEF(_MULTICASTTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _TAGPOOL_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_MULTICASTTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_MULTICASTTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _CRUMBSTORE_MCTO_ERR, _ENABLE); } static void _nvswitch_initialize_reduction_tstate_interrupts ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); chip_device->intr_mask.red_tstate.fatal = DRF_DEF(_REDUCTIONTSTATE, _ERR_FATAL_REPORT_EN_0, _TAGPOOL_ECC_DBE_ERR, _ENABLE) | DRF_DEF(_REDUCTIONTSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTORE_BUF_OVERWRITE_ERR, _ENABLE) | DRF_DEF(_REDUCTIONTSTATE, _ERR_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_DBE_ERR, _ENABLE); chip_device->intr_mask.red_tstate.nonfatal = DRF_DEF(_REDUCTIONTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _TAGPOOL_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_REDUCTIONTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _CRUMBSTORE_ECC_LIMIT_ERR, _ENABLE) | DRF_DEF(_REDUCTIONTSTATE, _ERR_NON_FATAL_REPORT_EN_0, _CRUMBSTORE_RTO_ERR, _ENABLE); } void _nvswitch_initialize_nport_interrupts_ls10 ( nvswitch_device *device ) { // Moving this L2 register access to SOE. Refer bug #3747687 #if 0 NvU32 val; val = DRF_NUM(_NPORT, _ERR_CONTROL_COMMON_NPORT, _CORRECTABLEENABLE, 1) | DRF_NUM(_NPORT, _ERR_CONTROL_COMMON_NPORT, _FATALENABLE, 1) | DRF_NUM(_NPORT, _ERR_CONTROL_COMMON_NPORT, _NONFATALENABLE, 1); NVSWITCH_NPORT_BCAST_WR32_LS10(device, _NPORT, _ERR_CONTROL_COMMON_NPORT, val); #endif // 0 _nvswitch_initialize_route_interrupts(device); _nvswitch_initialize_ingress_interrupts(device); _nvswitch_initialize_egress_interrupts(device); _nvswitch_initialize_tstate_interrupts(device); _nvswitch_initialize_sourcetrack_interrupts(device); _nvswitch_initialize_multicast_tstate_interrupts(device); _nvswitch_initialize_reduction_tstate_interrupts(device); } void _nvswitch_initialize_nxbar_interrupts_ls10 ( nvswitch_device *device ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 report_fatal; report_fatal = DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_BUFFER_OVERFLOW, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_BUFFER_UNDERFLOW, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _EGRESS_CREDIT_OVERFLOW, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _EGRESS_CREDIT_UNDERFLOW, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_NON_BURSTY_PKT, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_NON_STICKY_PKT, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_BURST_GT_9_DATA_VC, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_PKT_INVALID_DST, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_PKT_PARITY_ERROR, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_SIDEBAND_PARITY_ERROR, 1) | DRF_NUM(_NXBAR_TILE, _ERR_FATAL_INTR_EN, _INGRESS_REDUCTION_PKT_ERROR, 1); // Moving this L2 register access to SOE. Refer bug #3747687 #if 0 NVSWITCH_BCAST_WR32_LS10(device, NXBAR, _NXBAR_TILE, _ERR_FATAL_INTR_EN, report_fatal); #endif // 0 chip_device->intr_mask.tile.fatal = report_fatal; chip_device->intr_mask.tile.nonfatal = 0; report_fatal = DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _INGRESS_BUFFER_OVERFLOW, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _INGRESS_BUFFER_UNDERFLOW, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _EGRESS_CREDIT_OVERFLOW, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _EGRESS_CREDIT_UNDERFLOW, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _INGRESS_NON_BURSTY_PKT, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _INGRESS_NON_STICKY_PKT, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _INGRESS_BURST_GT_9_DATA_VC, 1) | DRF_NUM(_NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, _EGRESS_CDT_PARITY_ERROR, 1); // Moving this L2 register access to SOE. Refer bug #3747687 #if 0 NVSWITCH_BCAST_WR32_LS10(device, NXBAR, _NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, report_fatal); #endif // 0 chip_device->intr_mask.tileout.fatal = report_fatal; chip_device->intr_mask.tileout.nonfatal = 0; } /* * @brief Service MINION Falcon interrupts on the requested interrupt tree * Falcon Interrupts are a little unique in how they are handled:#include * IRQSTAT is used to read in interrupt status from FALCON * IRQMASK is used to read in mask of interrupts * IRQDEST is used to read in enabled interrupts that are routed to the HOST * * IRQSTAT & IRQMASK gives the pending interrupting on this minion * * @param[in] device MINION on this device * @param[in] instance MINION instance * */ NvlStatus nvswitch_minion_service_falcon_interrupts_ls10 ( nvswitch_device *device, NvU32 instance ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled, intr, link; link = instance * NVSWITCH_LINKS_PER_MINION_LS10; report.raw_pending = NVSWITCH_MINION_RD32_LS10(device, instance, _CMINION, _FALCON_IRQSTAT); report.raw_enable = chip_device->intr_minion_dest; report.mask = NVSWITCH_MINION_RD32_LS10(device, instance, _CMINION, _FALCON_IRQMASK); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; bit = DRF_NUM(_CMINION_FALCON, _IRQSTAT, _WDTMR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_MINION_WATCHDOG, "MINION Watchdog timer ran out", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_CMINION_FALCON, _IRQSTAT, _HALT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_MINION_HALT, "MINION HALT", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_CMINION_FALCON, _IRQSTAT, _EXTERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_MINION_EXTERR, "MINION EXTERR", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_CMINION_FALCON, _IRQSTAT, _SWGEN0, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_PRINT(device, INFO, "%s: Received MINION Falcon SWGEN0 interrupt on MINION %d.\n", __FUNCTION__, instance); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_CMINION_FALCON, _IRQSTAT, _SWGEN1, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_PRINT(device, INFO, "%s: Received MINION Falcon SWGEN1 interrupt on MINION %d.\n", __FUNCTION__, instance); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (device->link[link].fatal_error_occurred) { intr = NVSWITCH_MINION_RD32_LS10(device, instance, _MINION, _MINION_INTR_STALL_EN); intr = FLD_SET_DRF(_MINION, _MINION_INTR_STALL_EN, _FATAL, _DISABLE, intr); intr = FLD_SET_DRF(_MINION, _MINION_INTR_STALL_EN, _FALCON_STALL, _DISABLE, intr); intr = FLD_SET_DRF(_MINION, _MINION_INTR_STALL_EN, _FATAL, _DISABLE, intr); intr = FLD_SET_DRF(_MINION, _MINION_INTR_STALL_EN, _NONFATAL, _DISABLE, intr); NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _MINION_INTR_STALL_EN, intr); } // Write to IRQSCLR to clear status of interrupt NVSWITCH_MINION_WR32_LS10(device, instance, _CMINION, _FALCON_IRQSCLR, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } /* * @Brief : Send priv ring command and wait for completion * * @Description : * * @param[in] device a reference to the device to initialize * @param[in] cmd encoded priv ring command */ static NvlStatus _nvswitch_ring_master_cmd_ls10 ( nvswitch_device *device, NvU32 cmd ) { NvU32 value; NVSWITCH_TIMEOUT timeout; NvBool keepPolling; NVSWITCH_ENG_WR32(device, PRI_MASTER_RS, , 0, _PPRIV_MASTER, _RING_COMMAND, cmd); nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout); do { keepPolling = (nvswitch_timeout_check(&timeout)) ? NV_FALSE : NV_TRUE; value = NVSWITCH_ENG_RD32(device, PRI_MASTER_RS, , 0, _PPRIV_MASTER, _RING_COMMAND); if (FLD_TEST_DRF(_PPRIV_MASTER, _RING_COMMAND, _CMD, _NO_CMD, value)) { break; } nvswitch_os_sleep(1); } while (keepPolling); if (!FLD_TEST_DRF(_PPRIV_MASTER, _RING_COMMAND, _CMD, _NO_CMD, value)) { NVSWITCH_PRINT(device, ERROR, "%s: Timeout waiting for RING_COMMAND == NO_CMD (cmd=0x%x).\n", __FUNCTION__, cmd); return -NVL_INITIALIZATION_TOTAL_FAILURE; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_priv_ring_ls10 ( nvswitch_device *device ) { NvU32 pending, i; NVSWITCH_PRI_ERROR_LOG_TYPE pri_error; NvlStatus status = NVL_SUCCESS; pending = NVSWITCH_ENG_RD32(device, PRI_MASTER_RS, , 0, _PPRIV_MASTER, _RING_INTERRUPT_STATUS0); if (pending == 0) { return -NVL_NOT_FOUND; } // // SYS // if (FLD_TEST_DRF_NUM(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_SYS, 1, pending)) { pri_error.addr = NVSWITCH_ENG_RD32(device, SYS_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_ADR); pri_error.data = NVSWITCH_ENG_RD32(device, SYS_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_WRDAT); pri_error.info = NVSWITCH_ENG_RD32(device, SYS_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_INFO); pri_error.code = NVSWITCH_ENG_RD32(device, SYS_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_CODE); NVSWITCH_REPORT_PRI_ERROR_NONFATAL(_HW_HOST_PRIV_ERROR, "PRI WRITE SYS error", NVSWITCH_PPRIV_WRITE_SYS, 0, pri_error); NVSWITCH_PRINT(device, ERROR, "SYS PRI write error addr: 0x%08x data: 0x%08x info: 0x%08x code: 0x%08x\n", pri_error.addr, pri_error.data, pri_error.info, pri_error.code); pending = FLD_SET_DRF_NUM(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_SYS, 0, pending); } // // SYSB // if (FLD_TEST_DRF_NUM(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_SYSB, 1, pending)) { pri_error.addr = NVSWITCH_ENG_RD32(device, SYSB_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_ADR); pri_error.data = NVSWITCH_ENG_RD32(device, SYSB_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_WRDAT); pri_error.info = NVSWITCH_ENG_RD32(device, SYSB_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_INFO); pri_error.code = NVSWITCH_ENG_RD32(device, SYSB_PRI_HUB, , 0, _PPRIV_SYS, _PRIV_ERROR_CODE); NVSWITCH_REPORT_PRI_ERROR_NONFATAL(_HW_HOST_PRIV_ERROR, "PRI WRITE SYSB error", NVSWITCH_PPRIV_WRITE_SYS, 1, pri_error); NVSWITCH_PRINT(device, ERROR, "SYSB PRI write error addr: 0x%08x data: 0x%08x info: 0x%08x code: 0x%08x\n", pri_error.addr, pri_error.data, pri_error.info, pri_error.code); pending = FLD_SET_DRF_NUM(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_SYSB, 0, pending); } // // per-PRT // for (i = 0; i < NUM_PRT_PRI_HUB_ENGINE_LS10; i++) { if (DRF_VAL(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_FBP, pending) & NVBIT(i)) { pri_error.addr = NVSWITCH_ENG_RD32(device, PRT_PRI_HUB, , i, _PPRIV_PRT, _PRIV_ERROR_ADR); pri_error.data = NVSWITCH_ENG_RD32(device, PRT_PRI_HUB, , i, _PPRIV_PRT, _PRIV_ERROR_WRDAT); pri_error.info = NVSWITCH_ENG_RD32(device, PRT_PRI_HUB, , i, _PPRIV_PRT, _PRIV_ERROR_INFO); pri_error.code = NVSWITCH_ENG_RD32(device, PRT_PRI_HUB, , i, _PPRIV_PRT, _PRIV_ERROR_CODE); NVSWITCH_REPORT_PRI_ERROR_NONFATAL(_HW_HOST_PRIV_ERROR, "PRI WRITE PRT error", NVSWITCH_PPRIV_WRITE_PRT, i, pri_error); NVSWITCH_PRINT(device, ERROR, "PRT%d PRI write error addr: 0x%08x data: 0x%08x info: 0x%08x code: 0x%08x\n", i, pri_error.addr, pri_error.data, pri_error.info, pri_error.code); pending &= ~DRF_NUM(_PPRIV_MASTER, _RING_INTERRUPT_STATUS0, _GBL_WRITE_ERROR_FBP, NVBIT(i)); } } if (pending != 0) { NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_PRIV_ERROR, "Fatal, Unexpected PRI error\n"); NVSWITCH_LOG_FATAL_DATA(device, _HW, _HW_HOST_PRIV_ERROR, 2, 0, NV_FALSE, &pending); NVSWITCH_PRINT(device, ERROR, "Unexpected PRI error 0x%08x\n", pending); return -NVL_MORE_PROCESSING_REQUIRED; } // acknowledge the interrupt to the ringmaster status = _nvswitch_ring_master_cmd_ls10(device, DRF_DEF(_PPRIV_MASTER, _RING_COMMAND, _CMD, _ACK_INTERRUPT)); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, ERROR, "Timeout ACK'ing PRI error\n"); // // Don't return error code -- there is nothing kernel SW can do about it if ACK failed. // Likely it is PLM protected and SOE needs to handle it. // } return NVL_SUCCESS; } static NvlStatus _nvswitch_collect_nport_error_info_ls10 ( nvswitch_device *device, NvU32 link, NVSWITCH_RAW_ERROR_LOG_TYPE *data, NvU32 *idx, NvU32 register_start, NvU32 register_end ) { NvU32 register_block_size; NvU32 i = *idx; if ((register_start > register_end) || (register_start % sizeof(NvU32) != 0) || (register_end % sizeof(NvU32) != 0)) { return -NVL_BAD_ARGS; } register_block_size = (register_end - register_start)/sizeof(NvU32) + 1; if ((i + register_block_size > NVSWITCH_RAW_ERROR_LOG_DATA_SIZE) || (register_block_size > NVSWITCH_RAW_ERROR_LOG_DATA_SIZE)) { return -NVL_BAD_ARGS; } do { data->data[i] = NVSWITCH_ENG_OFF_RD32(device, NPORT, , link, register_start); register_start += sizeof(NvU32); i++; } while (register_start <= register_end); *idx = i; return NVL_SUCCESS; } static void _nvswitch_collect_error_info_ls10 ( nvswitch_device *device, NvU32 link, NvU32 collect_flags, // NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_* NVSWITCH_RAW_ERROR_LOG_TYPE *data ) { NvU32 val; NvU32 i = 0; NvlStatus status = NVL_SUCCESS; // // The requested data 'collect_flags' is captured, if valid. // if the error log buffer fills, then the currently captured data block // could be truncated and subsequent blocks will be skipped. // The 'flags' field in the log structure describes which blocks are // actually captured. // Captured blocks are packed, in order. // data->flags = 0; // ROUTE if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_ROUTE_ERR_TIMESTAMP_LOG, NV_ROUTE_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME; NVSWITCH_PRINT(device, INFO, "ROUTE: TIMESTAMP: 0x%08x\n", data->data[i-1]); } } val = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_HEADER_LOG_VALID); if (FLD_TEST_DRF_NUM(_ROUTE, _ERR_HEADER_LOG_VALID, _HEADERVALID0, 1, val)) { if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_ROUTE_ERR_MISC_LOG_0, NV_ROUTE_ERR_MISC_LOG_0); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC; NVSWITCH_PRINT(device, INFO, "ROUTE: MISC: 0x%08x\n", data->data[i-1]); } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_ROUTE_ERR_HEADER_LOG_4, NV_ROUTE_ERR_HEADER_LOG_10); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR; NVSWITCH_PRINT(device, INFO, "ROUTE: HEADER: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", data->data[i-8], data->data[i-7], data->data[i-6], data->data[i-5], data->data[i-4], data->data[i-3], data->data[i-2], data->data[i-1]); } } } // INGRESS if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_INGRESS_ERR_TIMESTAMP_LOG, NV_INGRESS_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME; NVSWITCH_PRINT(device, INFO, "INGRESS: TIMESTAMP: 0x%08x\n", data->data[i-1]); } } val = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_HEADER_LOG_VALID); if (FLD_TEST_DRF_NUM(_INGRESS, _ERR_HEADER_LOG_VALID, _HEADERVALID0, 1, val)) { if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_INGRESS_ERR_MISC_LOG_0, NV_INGRESS_ERR_MISC_LOG_0); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC; NVSWITCH_PRINT(device, INFO, "INGRESS: MISC: 0x%08x\n", data->data[i-1]); } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_INGRESS_ERR_HEADER_LOG_4, NV_INGRESS_ERR_HEADER_LOG_9); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR; NVSWITCH_PRINT(device, INFO, "INGRESS: HEADER: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", data->data[i-7], data->data[i-6], data->data[i-5], data->data[i-4], data->data[i-3], data->data[i-2], data->data[i-1]); } } } // EGRESS if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_ERR_TIMESTAMP_LOG, NV_EGRESS_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME; NVSWITCH_PRINT(device, INFO, "EGRESS: TIMESTAMP: 0x%08x\n", data->data[i-1]); } } val = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_HEADER_LOG_VALID); if (FLD_TEST_DRF_NUM(_EGRESS, _ERR_HEADER_LOG_VALID, _HEADERVALID0, 1, val)) { if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_ERR_MISC_LOG_0, NV_EGRESS_ERR_MISC_LOG_0); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC; NVSWITCH_PRINT(device, INFO, "EGRESS: MISC: 0x%08x\n", data->data[i-1]); } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_ERR_HEADER_LOG_4, NV_EGRESS_ERR_HEADER_LOG_10); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR; NVSWITCH_PRINT(device, INFO, "EGRESS: HEADER: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", data->data[i-7], data->data[i-6], data->data[i-5], data->data[i-4], data->data[i-3], data->data[i-2], data->data[i-1]); } } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_MC_ERR_TIMESTAMP_LOG, NV_EGRESS_MC_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_TIME; NVSWITCH_PRINT(device, INFO, "EGRESS: TIME MC: 0x%08x\n", data->data[i-1]); } } val = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _MC_ERR_HEADER_LOG_VALID); if (FLD_TEST_DRF_NUM(_EGRESS, _MC_ERR_HEADER_LOG_VALID, _HEADERVALID0, 1, val)) { if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_MISC) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_MC_ERR_MISC_LOG_0, NV_EGRESS_MC_ERR_MISC_LOG_0); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_MISC; NVSWITCH_PRINT(device, INFO, "EGRESS: MISC MC: 0x%08x\n", data->data[i-1]); } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_HDR) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_EGRESS_MC_ERR_HEADER_LOG_4, NV_EGRESS_MC_ERR_HEADER_LOG_10); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_HDR; NVSWITCH_PRINT(device, INFO, "EGRESS MC: HEADER: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", data->data[i-7], data->data[i-6], data->data[i-5], data->data[i-4], data->data[i-3], data->data[i-2], data->data[i-1]); } } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_MC_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_MULTICASTTSTATE_ERR_TIMESTAMP_LOG, NV_MULTICASTTSTATE_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_MC_TIME; NVSWITCH_PRINT(device, INFO, "MC TSTATE MC: 0x%08x\n", data->data[i-1]); } } if (collect_flags & NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_RED_TIME) { status = _nvswitch_collect_nport_error_info_ls10(device, link, data, &i, NV_REDUCTIONTSTATE_ERR_TIMESTAMP_LOG, NV_REDUCTIONTSTATE_ERR_TIMESTAMP_LOG); if (status == NVL_SUCCESS) { data->flags |= NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_RED_TIME; NVSWITCH_PRINT(device, INFO, "MC TSTATE RED: 0x%08x\n", data->data[i-1]); } } while (i < NVSWITCH_RAW_ERROR_LOG_DATA_SIZE) { data->data[i++] = 0; } } static NvlStatus _nvswitch_service_route_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.route.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_CONTAIN_EN_0); bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _ROUTEBUFERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_ROUTEBUFERR, "route buffer over/underflow", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_ROUTEBUFERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _GLT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_GLT_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_ROUTE_ERR_GLT, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_GLT_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_GLT_ECC_DBE_ERR, "route GLT DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_GLT_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_GLT_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _PDCTRLPARERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_PDCTRLPARERR, "route parity", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_PDCTRLPARERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _NVS_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_NVS_ECC_DBE_ERR, "route incoming DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_NVS_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_NVS_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_ROUTE, _ERR_STATUS_0, _NVS_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_STATUS_0, DRF_NUM(_ROUTE, _ERR_STATUS_0, _NVS_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _CDTPARERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_CDTPARERR, "route credit parity", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_CDTPARERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_CDTPARERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _MCRID_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_MCRID_ECC_DBE_ERR, "MC route ECC", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_MCRID_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_MCRID_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _EXTMCRID_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_EXTMCRID_ECC_DBE_ERR, "Extd MC route ECC", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_EXTMCRID_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_EXTMCRID_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _RAM_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_ROUTE_RAM_ECC_DBE_ERR, "route RAM ECC", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_ROUTE_RAM_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_RAM_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_ROUTE_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_route_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.route.nonfatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_FIRST_0); bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _NOPORTDEFINEDERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_NOPORTDEFINEDERR, "route undefined route"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_NOPORTDEFINEDERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _INVALIDROUTEPOLICYERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_HDR, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_INVALIDROUTEPOLICYERR, "route invalid policy"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_INVALIDROUTEPOLICYERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _NVS_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_ROUTE, _ERR_STATUS_0, _NVS_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_NVS_ECC_ERROR_COUNTER); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, "route incoming ECC limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _GLT_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_ROUTE, _ERR_STATUS_0, _GLT_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_GLT_ECC_ERROR_COUNTER); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, "GLT ECC limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_GLT_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_GLT_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _MCRID_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_ROUTE, _ERR_STATUS_0, _MCRID_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_MCRID_ECC_ERROR_COUNTER); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, "MCRID ECC limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_MCRID_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_MCRID_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _EXTMCRID_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_ROUTE, _ERR_STATUS_0, _EXTMCRID_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_EXTMCRID_ECC_ERROR_COUNTER); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_NVS_ECC_LIMIT_ERR, "EXTMCRID ECC limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_EXTMCRID_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_EXTMCRID_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_ROUTE, _ERR_STATUS_0, _RAM_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _ROUTE, _ERR_RAM_ECC_ERROR_COUNTER); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_RAM_ECC_LIMIT_ERR, "RAM ECC limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_RAM_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_ROUTE_RAM_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_ROUTE, _ERR_STATUS_0, _INVALID_MCRID_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_ROUTE_TIME, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_ROUTE_INVALID_MCRID_ERR, "invalid MC route"); NVSWITCH_REPORT_DATA(_HW_NPORT_ROUTE_INVALID_MCRID_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_STATUS_0, pending); // // Note, when traffic is flowing, if we reset ERR_COUNT before ERR_STATUS // register, we won't see an interrupt again until counter wraps around. // In that case, we will miss writing back many ECC victim entries. Hence, // always clear _ERR_COUNT only after _ERR_STATUS register is cleared! // NVSWITCH_ENG_WR32(device, NPORT, , link, _ROUTE, _ERR_NVS_ECC_ERROR_COUNTER, 0x0); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } // // Ingress // static NvlStatus _nvswitch_service_ingress_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.ingress[0].fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_CONTAIN_EN_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _CMDDECODEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_CMDDECODEERR, "ingress invalid command", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_CMDDECODEERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTAREMAPTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTAREMAPTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTAREMAPTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_DBE_ERR, "ingress ExtA remap DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_NCISOC_HDR_ECC_ERROR_COUNTER); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_NCISOC_HDR_ECC_DBE_ERR, "ingress header DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_NCISOC_HDR_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_NCISOC_HDR_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_HDR_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_STATUS_0, DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_HDR_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _INVALIDVCSET, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_INVALIDVCSET, "ingress invalid VCSet", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_INVALIDVCSET, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _REMAPTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_ADDRESS); if (FLD_TEST_DRF(_INGRESS_ERR_REMAPTAB, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_REMAPTAB_ECC_DBE_ERR, "ingress Remap DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_REMAPTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_REMAPTAB_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RIDTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_INGRESS_ERR_RIDTAB, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_RIDTAB_ECC_DBE_ERR, "ingress RID DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_RIDTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_RIDTAB_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RLANTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_INGRESS_ERR_RLANTAB, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_RLANTAB_ECC_DBE_ERR, "ingress RLAN DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_RLANTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_RLANTAB_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_NCISOC_PARITY_ERR, "ingress control parity", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_NCISOC_PARITY_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_NCISOC_PARITY_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTBREMAPTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTBREMAPTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTBREMAPTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_DBE_ERR, "ingress ExtB remap DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_MCREMAPTAB_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_MCREMAPTAB_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_MCREMAPTAB_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_INGRESS_MCREMAPTAB_ECC_DBE_ERR, "ingress MC remap DBE", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_MCREMAPTAB_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_INGRESS_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_ingress_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NvU32 pending_0, pending_1; NvU32 raw_pending_0; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; NvlStatus status = NVL_SUCCESS; // // _ERR_STATUS_0 // report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.ingress[0].nonfatal; raw_pending_0 = report.raw_pending; pending = (report.raw_pending & report.mask); pending_0 = pending; if (pending == 0) { goto _nvswitch_service_ingress_nonfatal_ls10_err_status_1; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_FIRST_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _REQCONTEXTMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_REQCONTEXTMISMATCHERR, "ingress request context mismatch"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_REQCONTEXTMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _ACLFAIL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_ACLFAIL, "ingress invalid ACL"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_ACLFAIL, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_HDR_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_INGRESS, _ERR_STATUS_0, _NCISOC_HDR_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_NCISOC_HDR_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_NCISOC_HDR_ECC_LIMIT_ERR, "ingress header ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_NCISOC_HDR_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_NCISOC_HDR_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _ADDRBOUNDSERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_ADDRBOUNDSERR, "ingress address bounds"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_ADDRBOUNDSERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RIDTABCFGERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_RIDTABCFGERR, "ingress RID packet"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_RIDTABCFGERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RLANTABCFGERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_RLANTABCFGERR, "ingress RLAN packet"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_RLANTABCFGERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _REMAPTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_INGRESS, _ERR_STATUS_0, _REMAPTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_REMAPTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_REMAPTAB_ECC_LIMIT_ERR, "ingress remap ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_REMAPTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_REMAPTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RIDTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_INGRESS, _ERR_STATUS_0, _RIDTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RIDTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_RIDTAB_ECC_LIMIT_ERR, "ingress RID ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_RIDTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_RIDTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _RLANTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_INGRESS, _ERR_STATUS_0, _RLANTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_RLANTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_RLANTAB_ECC_LIMIT_ERR, "ingress RLAN ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_RLANTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_RLANTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _ADDRTYPEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_ADDRTYPEERR, "ingress illegal address"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_ADDRTYPEERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_INDEX_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_INDEX_ERR, "ingress ExtA remap index"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_INDEX_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_INDEX_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_INDEX_ERR, "ingress ExtB remap index"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_INDEX_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_INDEX_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_INDEX_ERR, "ingress MC remap index"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_INDEX_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_REQCONTEXTMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_REQCONTEXTMISMATCHERR, "ingress ExtA request context mismatch"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_REQCONTEXTMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_REQCONTEXTMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_REQCONTEXTMISMATCHERR, "ingress ExtB request context mismatch"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_REQCONTEXTMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_REQCONTEXTMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_REQCONTEXTMISMATCHERR, "ingress MC request context mismatch"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_REQCONTEXTMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_ACLFAIL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_ACLFAIL, "ingress invalid ExtA ACL"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_ACLFAIL, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_ACLFAIL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_ACLFAIL, "ingress invalid ExtB ACL"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_ACLFAIL, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_ACLFAIL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_ACLFAIL, "ingress invalid MC ACL"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_ACLFAIL, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_ADDRBOUNDSERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_ADDRBOUNDSERR, "ingress ExtA address bounds"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_ADDRBOUNDSERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_ADDRBOUNDSERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_ADDRBOUNDSERR, "ingress ExtB address bounds"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_ADDRBOUNDSERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_ADDRBOUNDSERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_ADDRBOUNDSERR, "ingress MC address bounds"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_ADDRBOUNDSERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_FIRST_0, report.raw_first & report.mask); } if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } _nvswitch_service_ingress_nonfatal_ls10_err_status_1: // // _ERR_STATUS_1 // report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_STATUS_1); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_NON_FATAL_REPORT_EN_1); report.mask = report.raw_enable & chip_device->intr_mask.ingress[1].nonfatal; pending = (report.raw_pending & report.mask); pending_1 = pending; if ((pending_0 == 0) && (pending_1 == 0)) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_FIRST_1); bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _EXTAREMAPTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(raw_pending_0, DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTAREMAPTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTAREMAPTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_LIMIT_ERR, "ingress ExtA remap ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_EXTAREMAPTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _EXTBREMAPTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(raw_pending_0, DRF_NUM(_INGRESS, _ERR_STATUS_0, _EXTBREMAPTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_EXTBREMAPTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_LIMIT_ERR, "ingress ExtB remap ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_EXTBREMAPTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _MCREMAPTAB_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(raw_pending_0, DRF_NUM(_INGRESS, _ERR_STATUS_0, _MCREMAPTAB_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _INGRESS, _ERR_MCREMAPTAB_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_ECC_LIMIT_ERR, "ingress MC remap ECC"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_INGRESS_MCREMAPTAB_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _MCCMDTOUCADDRERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCCMDTOUCADDRERR, "ingress MC command to uc"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCCMDTOUCADDRERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _READMCREFLECTMEMERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_READMCREFLECTMEMERR, "ingress read reflective"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_READMCREFLECTMEMERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _EXTAREMAPTAB_ADDRTYPEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTAREMAPTAB_ADDRTYPEERR, "ingress ExtA address type"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTAREMAPTAB_ADDRTYPEERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _EXTBREMAPTAB_ADDRTYPEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_EXTBREMAPTAB_ADDRTYPEERR, "ingress ExtB address type"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_EXTBREMAPTAB_ADDRTYPEERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_INGRESS, _ERR_STATUS_1, _MCREMAPTAB_ADDRTYPEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_INGRESS_MCREMAPTAB_ADDRTYPEERR, "ingress MC address type"); NVSWITCH_REPORT_DATA(_HW_NPORT_INGRESS_MCREMAPTAB_ADDRTYPEERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_NON_FATAL_REPORT_EN_1, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_STATUS_0, pending_0); NVSWITCH_ENG_WR32(device, NPORT, , link, _INGRESS, _ERR_STATUS_1, pending_1); if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } return status; } // // Tstate // static NvlStatus _nvswitch_service_tstate_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.tstate.nonfatal; report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_MISC_LOG_0); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_FIRST_0); bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_TSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_TSTATE_TAGPOOL_ECC_LIMIT_ERR, "TS tag store single-bit threshold"); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_DATA(_HW_NPORT_TSTATE_TAGPOOL_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_TSTATE_TAGPOOL_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_TSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_TSTATE_CRUMBSTORE_ECC_LIMIT_ERR, "TS crumbstore single-bit threshold"); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); NVSWITCH_REPORT_DATA(_HW_NPORT_TSTATE_CRUMBSTORE_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_TSTATE_CRUMBSTORE_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_tstate_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.tstate.fatal; report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_MISC_LOG_0); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CONTAIN_EN_0); bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOLBUFERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_TAGPOOLBUFERR, "TS pointer crossover", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_TSTATE_TAGPOOLBUFERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_TSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_TSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_TAGPOOL_ECC_DBE_ERR, "TS tag store fatal ECC", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_TSTATE_TAGPOOL_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_TSTATE_TAGPOOL_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0, DRF_NUM(_TSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTOREBUFERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_CRUMBSTOREBUFERR, "TS crumbstore", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_TSTATE_CRUMBSTOREBUFERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_TSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_TSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_CRUMBSTORE_ECC_DBE_ERR, "TS crumbstore fatal ECC", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_TSTATE_CRUMBSTORE_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_TSTATE_CRUMBSTORE_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0, DRF_NUM(_TSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _ATO_ERR, 1); if (nvswitch_test_flags(pending, bit)) { if (FLD_TEST_DRF_NUM(_TSTATE, _ERR_FIRST_0, _ATO_ERR, 1, report.raw_first)) { report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _TSTATE, _ERR_DEBUG); } NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_ATO_ERR, "TS ATO timeout", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_TSTATE, _ERR_STATUS_0, _CAMRSP_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_TSTATE_CAMRSP_ERR, "Rsp Tag value out of range", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_TSTATE_CAMRSP_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_TSTATE_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _TSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } // // Egress // static NvlStatus _nvswitch_service_egress_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NvU32 pending_0, pending_1; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; NvlStatus status = NVL_SUCCESS; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.egress[0].nonfatal; pending = report.raw_pending & report.mask; pending_0 = pending; if (pending == 0) { goto _nvswitch_service_egress_nonfatal_ls10_err_status_1; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FIRST_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_ECC_DBE_ERR, 1)))) { report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_NXBAR_ECC_ERROR_COUNTER); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_NXBAR_HDR_ECC_LIMIT_ERR, "egress input ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_NXBAR_HDR_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NXBAR_HDR_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _RAM_OUT_HDR_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_0, _RAM_OUT_HDR_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_EGRESS_ERR_RAM_OUT, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_ADDRESS); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_LIMIT_ERR, "egress output ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _PRIVRSPERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_PRIVRSPERR, "egress non-posted PRIV error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_PRIVRSPERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0, pending); // HACK: Clear all pending interrupts! NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0, 0xFFFFFFFF); if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } _nvswitch_service_egress_nonfatal_ls10_err_status_1: report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_NON_FATAL_REPORT_EN_1); report.mask = report.raw_enable & chip_device->intr_mask.egress[1].nonfatal; pending = report.raw_pending & report.mask; pending_1 = pending; if ((pending_0 == 0) && (pending_1 == 0)) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FIRST_1); bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, "egress reduction header ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_NXBAR_HDR_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSPCTRLSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSPCTRLSTORE_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_LIMIT_ERR, "egress MC response ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBCTRLSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBCTRLSTORE_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_LIMIT_ERR, "egress RB ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDSGT_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDSGT_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCREDSGT_ECC_LIMIT_ERR, "egress RSG ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCREDSGT_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCREDSGT_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDBUF_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDBUF_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCREDBUF_ECC_LIMIT_ERR, "egress MCRB ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCREDBUF_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCREDBUF_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_RAM_HDR_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_RAM_HDR_ECC_DBE_ERR, 1)))) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_LIMIT_ERR, "egress MC header ECC error limit"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_LIMIT_ERR, link, NV_FALSE, 0, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_ECC_DBE_ERR, "egress reduction header ECC DBE error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_HDR_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_PARITY_ERR, "egress reduction header parity error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_NXBAR_REDUCTION_HDR_PARITY_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _NXBAR_REDUCTION_FLITTYPE_MISMATCH_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_NXBAR_REDUCTION_FLITTYPE_MISMATCH_ERR, "egress reduction flit mismatch error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_NXBAR_REDUCTION_FLITTYPE_MISMATCH_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDBUF_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCREDBUF_ECC_DBE_ERR, "egress reduction buffer ECC DBE error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCREDBUF_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCREDBUF_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDBUF_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDBUF_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_CNT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_HDR, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_MCRSP_CNT_ERR, "egress MC response count error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_MCRSP_CNT_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBRSP_CNT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MC_HDR, &data); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_EGRESS_RBRSP_CNT_ERR, "egress reduction response count error"); NVSWITCH_REPORT_DATA(_HW_NPORT_EGRESS_RBRSP_CNT_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_NON_FATAL_REPORT_EN_1, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, pending); // Clear all pending interrupts! NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, 0xFFFFFFFF); if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } return status; } static NvlStatus _nvswitch_service_egress_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NvU32 pending_0, pending_1; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; NVSWITCH_RAW_ERROR_LOG_TYPE credit_data = {0, { 0 }}; NVSWITCH_RAW_ERROR_LOG_TYPE buffer_data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; NvlStatus status = NVL_SUCCESS; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.egress[0].fatal; pending = report.raw_pending & report.mask; pending_0 = pending; if (pending == 0) { goto _nvswitch_service_egress_fatal_ls10_err_status_1; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_CONTAIN_EN_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _EGRESSBUFERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_EGRESSBUFERR, "egress crossbar overflow", NV_TRUE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_EGRESSBUFERR, data); buffer_data.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS0); buffer_data.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS1); buffer_data.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS2); buffer_data.data[3] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS3); buffer_data.data[4] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS4); buffer_data.data[5] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS5); buffer_data.data[6] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS6); buffer_data.data[7] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _BUFFER_POINTERS7); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_EGRESSBUFERR, buffer_data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _PKTROUTEERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_PKTROUTEERR, "egress packet route", NV_TRUE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_PKTROUTEERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _SEQIDERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_SEQIDERR, "egress sequence ID error", NV_TRUE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_SEQIDERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NXBAR_HDR_ECC_DBE_ERR, "egress input ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NXBAR_HDR_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NXBAR_HDR_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0, DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _RAM_OUT_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_EGRESS_ERR_RAM_OUT, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_RAM_OUT_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_DBE_ERR, "egress output ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_RAM_OUT_HDR_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_0, _RAM_OUT_HDR_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0, DRF_NUM(_EGRESS, _ERR_STATUS_0, _RAM_OUT_HDR_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NCISOCCREDITOVFL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NCISOCCREDITOVFL, "egress credit overflow", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NCISOCCREDITOVFL, data); credit_data.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT0); credit_data.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT1); credit_data.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT2); credit_data.data[3] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT3); credit_data.data[4] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT4); credit_data.data[5] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT5); credit_data.data[6] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT6); credit_data.data[7] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT7); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NCISOCCREDITOVFL, credit_data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _REQTGTIDMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_REQTGTIDMISMATCHERR, "egress destination request ID error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_REQTGTIDMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _RSPREQIDMISMATCHERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_RSPREQIDMISMATCHERR, "egress destination response ID error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_RSPREQIDMISMATCHERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _URRSPERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_DROPNPURRSPERR, "egress non-posted UR error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_DROPNPURRSPERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _HWRSPERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_HWRSPERR, "egress non-posted HW error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_HWRSPERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_HDR_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NXBAR_HDR_PARITY_ERR, "egress control parity error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NXBAR_HDR_PARITY_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NXBAR_HDR_PARITY_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NCISOC_CREDIT_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NCISOC_CREDIT_PARITY_ERR, "egress credit parity error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NCISOC_CREDIT_PARITY_ERR, data); credit_data.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT0); credit_data.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT1); credit_data.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT2); credit_data.data[3] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT3); credit_data.data[4] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT4); credit_data.data[5] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT5); credit_data.data[6] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT6); credit_data.data[7] = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _NCISOC_CREDIT7); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NCISOC_CREDIT_PARITY_ERR, credit_data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_NCISOC_CREDIT_PARITY_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_FLITTYPE_MISMATCH_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NXBAR_FLITTYPE_MISMATCH_ERR, "egress flit type mismatch", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NXBAR_FLITTYPE_MISMATCH_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _CREDIT_TIME_OUT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_CREDIT_TIME_OUT_ERR, "egress credit timeout", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_CREDIT_TIME_OUT_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _NXBAR_SIDEBAND_PD_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_NXBAR_SIDEBAND_PD_PARITY_ERR, "egress crossbar SB parity", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_NXBAR_SIDEBAND_PD_PARITY_ERR, data); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_EGRESS, _ERR_STATUS_0, _INVALIDVCSET_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_INVALIDVCSET_ERR, "egress invalid VC set", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_INVALIDVCSET_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_EGRESS_0_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_0, pending); if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } _nvswitch_service_egress_fatal_ls10_err_status_1: report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FATAL_REPORT_EN_1); report.mask = report.raw_enable & chip_device->intr_mask.egress[1].fatal; pending = report.raw_pending & report.mask; pending_1 = pending; if ((pending_0 == 0) && (pending_1 == 0)) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_FIRST_1); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _EGRESS, _ERR_CONTAIN_EN_1); bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSPCTRLSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_DBE_ERR, "egress MC response ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCRSPCTRLSTORE_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSPCTRLSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSPCTRLSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBCTRLSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_DBE_ERR, "egress reduction ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_RBCTRLSTORE_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBCTRLSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _RBCTRLSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDSGT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_MCREDSGT_ECC_DBE_ERR, "egress MC SG ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_MCREDSGT_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCREDSGT_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDSGT_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCREDSGT_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_RAM_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_DBE_ERR, "egress MC ram ECC DBE error", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_EGRESS_MCRSP_RAM_HDR_ECC_DBE_ERR, link, NV_FALSE, 0, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_RAM_HDR_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, DRF_NUM(_EGRESS, _ERR_STATUS_1, _MCRSP_RAM_HDR_ECC_LIMIT_ERR, 1)); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_EGRESS_1_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FATAL_REPORT_EN_1, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, pending); // Clear all pending interrupts! NVSWITCH_ENG_WR32(device, NPORT, , link, _EGRESS, _ERR_STATUS_1, 0xFFFFFFFF); if (unhandled != 0) { status = -NVL_MORE_PROCESSING_REQUIRED; } return status; } static NvlStatus _nvswitch_service_sourcetrack_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.sourcetrack.nonfatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_FIRST_0); bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if (!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _CREQ_TCEN0_CRUMBSTORE_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_SOURCETRACK_ERR_CREQ_TCEN0_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_COUNTER); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS); report.data[2] = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_SOURCETRACK_CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, "sourcetrack TCEN0 crumbstore ECC limit err"); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_SOURCETRACK_CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. // if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_sourcetrack_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.sourcetrack.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CONTAIN_EN_0); bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _CREQ_TCEN0_CRUMBSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_SOURCETRACK_ERR_CREQ_TCEN0_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[0] = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS); report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _SOURCETRACK, _ERR_CREQ_TCEN0_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_SOURCETRACK_CREQ_TCEN0_CRUMBSTORE_ECC_DBE_ERR, "sourcetrack TCEN0 crumbstore DBE", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_SOURCETRACK_CREQ_TCEN0_CRUMBSTORE_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_STATUS_0, DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _CREQ_TCEN0_CRUMBSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _DUP_CREQ_TCEN0_TAG_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_SOURCETRACK_DUP_CREQ_TCEN0_TAG_ERR, "sourcetrack duplicate CREQ", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _INVALID_TCEN0_RSP_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_SOURCETRACK_INVALID_TCEN0_RSP_ERR, "sourcetrack invalid TCEN0 CREQ", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _INVALID_TCEN1_RSP_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_SOURCETRACK_INVALID_TCEN1_RSP_ERR, "sourcetrack invalid TCEN1 CREQ", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_SOURCETRACK, _ERR_STATUS_0, _SOURCETRACK_TIME_OUT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_SOURCETRACK_SOURCETRACK_TIME_OUT_ERR, "sourcetrack timeout error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. // if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_SOURCETRACK_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _SOURCETRACK, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } // // Multicast Tstate // static NvlStatus _nvswitch_service_multicast_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.mc_tstate.nonfatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FIRST_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_MC_TIME, &data); bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_MULTICASTTSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_LIMIT_ERR, "MC TS tag store single-bit threshold"); NVSWITCH_REPORT_DATA(_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_MULTICASTTSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, "MC TS crumbstore single-bit threshold"); NVSWITCH_REPORT_DATA(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_MCTO_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_MCTO_ERR, "MC TS crumbstore MCTO"); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_DATA(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_MCTO_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_multicast_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.mc_tstate.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CONTAIN_EN_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_MC_TIME, &data); bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_MULTICASTTSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_MULTICASTTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_DBE_ERR, "MC TS tag store fatal ECC", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_MULTICASTTSTATE_TAGPOOL_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0, DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_MULTICASTTSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_MULTICASTTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_DBE_ERR, "MC TS crumbstore fatal ECC", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0, DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_MULTICASTTSTATE, _ERR_STATUS_0, _CRUMBSTORE_BUF_OVERWRITE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_BUF_OVERWRITE_ERR, "MC crumbstore overwrite", NV_FALSE); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_MULTICASTTSTATE_CRUMBSTORE_BUF_OVERWRITE_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_MULTICAST_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _MULTICASTTSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } // // Reduction Tstate // static NvlStatus _nvswitch_service_reduction_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.mc_tstate.nonfatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FIRST_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_RED_TIME, &data); bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_REDUCTIONTSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_LIMIT_ERR, "Red TS tag store single-bit threshold"); NVSWITCH_REPORT_DATA(_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { // Ignore LIMIT error if DBE is pending if(!(nvswitch_test_flags(report.raw_pending, DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1)))) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_REDUCTIONTSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_NONFATAL(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, "Red TS crumbstore single-bit threshold"); NVSWITCH_REPORT_DATA(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, data); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_LIMIT_ERR, link, bAddressValid, address, NV_FALSE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_RTO_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_RTO_ERR, "Red TS crumbstore RTO"); NVSWITCH_REPORT_DATA(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_RTO_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_reduction_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NVSWITCH_RAW_ERROR_LOG_TYPE data = {0, { 0 }}; INFOROM_NVS_ECC_ERROR_EVENT err_event = {0}; report.raw_pending = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & chip_device->intr_mask.mc_tstate.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CONTAIN_EN_0); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_RED_TIME, &data); bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_REDUCTIONTSTATE_ERR_TAGPOOL, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, DRF_DEF(_REDUCTIONTSTATE, _ERR_TAGPOOL_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_DBE_ERR, "Red TS tag store fatal ECC", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_EGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_REDUCTIONTSTATE_TAGPOOL_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0, DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _TAGPOOL_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NvBool bAddressValid = NV_FALSE; NvU32 address = 0; NvU32 addressValid = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS_VALID); if (FLD_TEST_DRF(_REDUCTIONTSTATE_ERR_CRUMBSTORE, _ECC_ERROR_ADDRESS_VALID, _VALID, _VALID, addressValid)) { address = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_ADDRESS); bAddressValid = NV_TRUE; } report.data[1] = NVSWITCH_ENG_RD32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER); NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, DRF_DEF(_REDUCTIONTSTATE, _ERR_CRUMBSTORE_ECC_ERROR_COUNTER, _ERROR_COUNT, _INIT)); NVSWITCH_REPORT_CONTAIN(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_DBE_ERR, "Red TS crumbstore fatal ECC", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_DBE_ERR, data); nvswitch_clear_flags(&unhandled, bit); _nvswitch_construct_ecc_error_event_ls10(&err_event, NVSWITCH_ERR_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_ECC_DBE_ERR, link, bAddressValid, address, NV_TRUE, 1); nvswitch_inforom_ecc_log_err_event(device, &err_event); // Clear associated LIMIT_ERR interrupt if (report.raw_pending & DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)) { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0, DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_ECC_LIMIT_ERR, 1)); } } bit = DRF_NUM(_REDUCTIONTSTATE, _ERR_STATUS_0, _CRUMBSTORE_BUF_OVERWRITE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_CONTAIN(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_BUF_OVERWRITE_ERR, "Red crumbstore overwrite", NV_FALSE); _nvswitch_collect_error_info_ls10(device, link, NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_TIME | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_MISC | NVSWITCH_RAW_ERROR_LOG_DATA_FLAG_INGRESS_HDR, &data); NVSWITCH_REPORT_CONTAIN_DATA(_HW_NPORT_REDUCTIONTSTATE_CRUMBSTORE_BUF_OVERWRITE_ERR, data); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. if (device->link[link].fatal_error_occurred) { if (nvswitch_is_soe_supported(device)) { nvswitch_soe_disable_nport_fatal_interrupts_ls10(device, link, report.raw_enable ^ pending, RM_SOE_CORE_NPORT_REDUCTION_INTERRUPT); } else { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } } if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NPORT, , link, _REDUCTIONTSTATE, _ERR_STATUS_0, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nport_fatal_ls10 ( nvswitch_device *device, NvU32 link ) { NvlStatus status[7]; status[0] = _nvswitch_service_route_fatal_ls10(device, link); status[1] = _nvswitch_service_ingress_fatal_ls10(device, link); status[2] = _nvswitch_service_egress_fatal_ls10(device, link); status[3] = _nvswitch_service_tstate_fatal_ls10(device, link); status[4] = _nvswitch_service_sourcetrack_fatal_ls10(device, link); status[5] = _nvswitch_service_multicast_fatal_ls10(device, link); status[6] = _nvswitch_service_reduction_fatal_ls10(device, link); if ((status[0] != NVL_SUCCESS) && (status[1] != NVL_SUCCESS) && (status[2] != NVL_SUCCESS) && (status[3] != NVL_SUCCESS) && (status[4] != NVL_SUCCESS) && (status[5] != NVL_SUCCESS) && (status[6] != NVL_SUCCESS)) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_npg_fatal_ls10 ( nvswitch_device *device, NvU32 npg ) { NvU32 pending, mask, bit, unhandled; NvU32 nport; NvU32 link; pending = NVSWITCH_ENG_RD32(device, NPG, , npg, _NPG, _NPG_INTERRUPT_STATUS); if (pending == 0) { return -NVL_NOT_FOUND; } mask = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV0_INT_STATUS, _FATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV1_INT_STATUS, _FATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV2_INT_STATUS, _FATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV3_INT_STATUS, _FATAL); pending &= mask; unhandled = pending; for (nport = 0; nport < NVSWITCH_NPORT_PER_NPG_LS10; nport++) { switch (nport) { case 0: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV0_INT_STATUS, _FATAL); break; case 1: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV1_INT_STATUS, _FATAL); break; case 2: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV2_INT_STATUS, _FATAL); break; case 3: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV3_INT_STATUS, _FATAL); break; } if (nvswitch_test_flags(pending, bit)) { link = NPORT_TO_LINK_LS10(device, npg, nport); if (NVSWITCH_ENG_IS_VALID(device, NPORT, link)) { if (_nvswitch_service_nport_fatal_ls10(device, link) == NVL_SUCCESS) { nvswitch_clear_flags(&unhandled, bit); } } } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nport_nonfatal_ls10 ( nvswitch_device *device, NvU32 link ) { NvlStatus status[7]; status[0] = _nvswitch_service_route_nonfatal_ls10(device, link); status[1] = _nvswitch_service_ingress_nonfatal_ls10(device, link); status[2] = _nvswitch_service_egress_nonfatal_ls10(device, link); status[3] = _nvswitch_service_tstate_nonfatal_ls10(device, link); status[4] = _nvswitch_service_sourcetrack_nonfatal_ls10(device, link); status[5] = _nvswitch_service_multicast_nonfatal_ls10(device, link); status[6] = _nvswitch_service_reduction_nonfatal_ls10(device, link); if ((status[0] != NVL_SUCCESS) && (status[1] != NVL_SUCCESS) && (status[2] != NVL_SUCCESS) && (status[3] != NVL_SUCCESS) && (status[4] != NVL_SUCCESS) && (status[5] != NVL_SUCCESS) && (status[6] != NVL_SUCCESS)) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_npg_nonfatal_ls10 ( nvswitch_device *device, NvU32 npg ) { NvU32 pending, mask, bit, unhandled; NvU32 nport; NvU32 link; pending = NVSWITCH_ENG_RD32(device, NPG, , npg, _NPG, _NPG_INTERRUPT_STATUS); if (pending == 0) { return -NVL_NOT_FOUND; } mask = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV0_INT_STATUS, _NONFATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV1_INT_STATUS, _NONFATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV2_INT_STATUS, _NONFATAL) | DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV3_INT_STATUS, _NONFATAL); pending &= mask; unhandled = pending; for (nport = 0; nport < NVSWITCH_NPORT_PER_NPG_LS10; nport++) { switch (nport) { case 0: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV0_INT_STATUS, _NONFATAL); break; case 1: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV1_INT_STATUS, _NONFATAL); break; case 2: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV2_INT_STATUS, _NONFATAL); break; case 3: bit = DRF_DEF(_NPG, _NPG_INTERRUPT_STATUS, _DEV3_INT_STATUS, _NONFATAL); break; } if (nvswitch_test_flags(pending, bit)) { link = NPORT_TO_LINK_LS10(device, npg, nport); if (NVSWITCH_ENG_IS_VALID(device, NPORT, link)) { if (_nvswitch_service_nport_nonfatal_ls10(device, link) == NVL_SUCCESS) { nvswitch_clear_flags(&unhandled, bit); } } } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvldl_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU64 intrLinkMask ) { NvU64 enabledLinkMask, localLinkMask, localIntrLinkMask, runtimeErrorMask = 0; NvU32 i; nvlink_link *link; NvU32 clocksMask = NVSWITCH_PER_LINK_CLOCK_SET(RXCLK) | NVSWITCH_PER_LINK_CLOCK_SET(TXCLK); NvlStatus status = -NVL_MORE_PROCESSING_REQUIRED; NVSWITCH_LINK_TRAINING_ERROR_INFO linkTrainingErrorInfo = { 0 }; NVSWITCH_LINK_RUNTIME_ERROR_INFO linkRuntimeErrorInfo = { 0 }; // // The passed in interruptLinkMask should contain a link that is part of the // given nvlipt instance // enabledLinkMask = nvswitch_get_enabled_link_mask(device); localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(nvlipt_instance); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { link = nvswitch_get_link(device, i); if (link == NULL) { // An interrupt on an invalid link should never occur NVSWITCH_ASSERT(link != NULL); continue; } if (NVSWITCH_GET_LINK_ENG_INST(device, i, NVLIPT) != nvlipt_instance) { NVSWITCH_ASSERT(0); break; } if (nvswitch_is_link_in_reset(device, link) || !nvswitch_are_link_clocks_on_ls10(device, link, clocksMask)) { continue; } if (device->hal.nvswitch_service_nvldl_fatal_link(device, nvlipt_instance, i) == NVL_SUCCESS) { runtimeErrorMask |= NVBIT64(i); status = NVL_SUCCESS; } } FOR_EACH_INDEX_IN_MASK_END; linkTrainingErrorInfo.isValid = NV_FALSE; linkRuntimeErrorInfo.isValid = NV_TRUE; linkRuntimeErrorInfo.mask0 = runtimeErrorMask; // Check runtimeErrorMask is non-zero before consuming it further. if ((runtimeErrorMask != 0) && (nvswitch_smbpbi_set_link_error_info(device, &linkTrainingErrorInfo, &linkRuntimeErrorInfo) != NVL_SUCCESS)) { NVSWITCH_PRINT(device, ERROR, "%s: NVLDL[0x%x, 0x%llx]: Unable to send Runtime Error bitmask: 0x%llx,\n", __FUNCTION__, nvlipt_instance, localIntrLinkMask, runtimeErrorMask); } return status; } static NvlStatus _nvswitch_service_nvltlc_tx_sys_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _NCISOC_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_NCISOC_PARITY_ERR, "NCISOC Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_NCISOC_PARITY_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _NCISOC_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_NCISOC_HDR_ECC_DBE_ERR, "NCISOC HDR ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_NCISOC_HDR_ECC_DBE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _NCISOC_DAT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_NCISOC_DAT_ECC_DBE_ERR, "NCISOC DAT ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _NCISOC_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_NCISOC_ECC_LIMIT_ERR, "NCISOC ECC Limit Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _TXPOISONDET, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TXPOISONDET, "Poison Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _TXRSPSTATUS_HW_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_TXRSPSTATUS_HW_ERR, "TX Response Status HW Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _TXRSPSTATUS_UR_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_TXRSPSTATUS_UR_ERR, "TX Response Status UR Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_SYS, _ERR_STATUS_0, _TXRSPSTATUS_PRIV_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_SYS_TXRSPSTATUS_PRIV_ERR, "TX Response Status PRIV Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_SYS, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_TX_SYS interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_rx_sys_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _NCISOC_PARITY_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_NCISOC_PARITY_ERR, "NCISOC Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _HDR_RAM_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_HDR_RAM_ECC_DBE_ERR, "HDR RAM ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_RX_HDR_RAM_ECC_DBE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _HDR_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_HDR_RAM_ECC_LIMIT_ERR, "HDR RAM ECC Limit Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _DAT0_RAM_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_DAT0_RAM_ECC_DBE_ERR, "DAT0 RAM ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_RX_DAT0_RAM_ECC_DBE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _DAT0_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_DAT0_RAM_ECC_LIMIT_ERR, "DAT0 RAM ECC Limit Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _DAT1_RAM_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_DAT1_RAM_ECC_DBE_ERR, "DAT1 RAM ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_RX_DAT1_RAM_ECC_DBE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_SYS, _ERR_STATUS_0, _DAT1_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_SYS_DAT1_RAM_ECC_LIMIT_ERR, "DAT1 RAM ECC Limit Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_SYS, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_RX_SYS interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_tx_lnk_fatal_0_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _TXDLCREDITPARITYERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TXDLCREDITPARITYERR, "TX DL Credit Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_DL_CREDIT_PARITY_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _CREQ_RAM_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_LNK_CREQ_RAM_HDR_ECC_DBE_ERR, "CREQ RAM HDR ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP_RAM_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_LNK_RSP_RAM_HDR_ECC_DBE_ERR, "Response RAM HDR ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _COM_RAM_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_LNK_COM_RAM_HDR_ECC_DBE_ERR, "COM RAM HDR ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP1_RAM_HDR_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_LNK_RSP1_RAM_HDR_ECC_DBE_ERR, "RSP1 RAM HDR ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP1_RAM_DAT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_TX_LNK_RSP1_RAM_DAT_ECC_DBE_ERR, "RSP1 RAM DAT ECC DBE Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_TX_RSP1_DAT_RAM_ECC_DBE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_TX_LNK _0 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_rx_lnk_fatal_0_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXDLHDRPARITYERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXDLHDRPARITYERR, "RX DL HDR Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_DL_HDR_PARITY_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXDLDATAPARITYERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXDLDATAPARITYERR, "RX DL Data Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_DL_DATA_PARITY_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXDLCTRLPARITYERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXDLCTRLPARITYERR, "RX DL Ctrl Parity Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_DL_CTRL_PARITY_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXPKTLENERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXPKTLENERR, "RX Packet Length Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_PKTLEN_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RSVCACHEATTRPROBEREQERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RSVCACHEATTRPROBEREQERR, "RSV Packet Status Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_RSVD_CACHE_ATTR_PROBE_REQ_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RSVCACHEATTRPROBERSPERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RSVCACHEATTRPROBERSPERR, "RSV CacheAttr Probe Rsp Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_RSVD_CACHE_ATTR_PROBE_RSP_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _DATLENGTRMWREQMAXERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_DATLENGTRMWREQMAXERR, "Data Length RMW Req Max Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_DATLEN_GT_RMW_REQ_MAX_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _DATLENLTATRRSPMINERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_DATLENLTATRRSPMINERR, "Data Len Lt ATR RSP Min Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_DATLEN_LT_ATR_RSP_MIN_ERR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _INVALIDCACHEATTRPOERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_INVALIDCACHEATTRPOERR, "Invalid Cache Attr PO Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_INVALID_PO_FOR_CACHE_ATTR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXRSPSTATUS_HW_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_LNK_RXRSPSTATUS_HW_ERR, "RX Rsp Status HW Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_RSP_STATUS_HW_ERR_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXRSPSTATUS_UR_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_LNK_RXRSPSTATUS_UR_ERR, "RX Rsp Status UR Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_RSP_STATUS_UR_ERR_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _INVALID_COLLAPSED_RESPONSE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RX_LNK_INVALID_COLLAPSED_RESPONSE_ERR, "Invalid Collapsed Response Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_INVALID_COLLAPSED_RESPONSE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_RX_LNK _0 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_rx_lnk_fatal_1_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; NvU32 injected; report.raw_pending = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_1); report.raw_enable = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FATAL_REPORT_EN_1); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_1); injected = NVSWITCH_LINK_RD32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_REPORT_INJECT_1); bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _RXHDROVFERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXHDROVFERR, "RX HDR OVF Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); if (FLD_TEST_DRF_NUM(_NVLTLC, _RX_LNK_ERR_REPORT_INJECT_1, _RXHDROVFERR, 0x0, injected)) { error_event.error = INFOROM_NVLINK_TLC_RX_HDR_OVERFLOW_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _RXDATAOVFERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXDATAOVFERR, "RX Data OVF Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); if (FLD_TEST_DRF_NUM(_NVLTLC, _RX_LNK_ERR_REPORT_INJECT_1, _RXDATAOVFERR, 0x0, injected)) { error_event.error = INFOROM_NVLINK_TLC_RX_DATA_OVERFLOW_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _STOMPDETERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_STOMPDETERR, "Stomp Det Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); if (FLD_TEST_DRF_NUM(_NVLTLC, _RX_LNK_ERR_REPORT_INJECT_1, _STOMPDETERR, 0x0, injected)) { error_event.error = INFOROM_NVLINK_TLC_RX_STOMP_DETECTED_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _RXPOISONERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLTLC_RXPOISONERR, "RX Poison Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FATAL_REPORT_EN_1, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_LINK_WR32_LS10(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_1, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_RX_LNK _1 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } NvlStatus _nvswitch_service_nvltlc_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU64 intrLinkMask ) { NvU64 enabledLinkMask, localLinkMask, localIntrLinkMask; NvU32 i; nvlink_link *link; NvlStatus status = -NVL_MORE_PROCESSING_REQUIRED; // // The passed in interruptLinkMask should contain a link that is part of the // given nvlipt instance // enabledLinkMask = nvswitch_get_enabled_link_mask(device); localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(nvlipt_instance); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { link = nvswitch_get_link(device, i); if (link == NULL) { // An interrupt on an invalid link should never occur NVSWITCH_ASSERT(link != NULL); continue; } if (NVSWITCH_GET_LINK_ENG_INST(device, i, NVLIPT) != nvlipt_instance) { NVSWITCH_ASSERT(0); break; } // // If link is in reset or NCISOC clock is off then // don't need to check the link for NVLTLC errors // as the IP's registers are off // if (nvswitch_is_link_in_reset(device, link) || !nvswitch_are_link_clocks_on_ls10(device, link,NVSWITCH_PER_LINK_CLOCK_SET(NCISOCCLK))) { continue; } if (_nvswitch_service_nvltlc_tx_sys_fatal_ls10(device, nvlipt_instance, i) == NVL_SUCCESS) { status = NVL_SUCCESS; } if (_nvswitch_service_nvltlc_rx_sys_fatal_ls10(device, nvlipt_instance, i) == NVL_SUCCESS) { status = NVL_SUCCESS; } if (_nvswitch_service_nvltlc_tx_lnk_fatal_0_ls10(device, nvlipt_instance, i) == NVL_SUCCESS) { status = NVL_SUCCESS; } if (_nvswitch_service_nvltlc_rx_lnk_fatal_0_ls10(device, nvlipt_instance, i) == NVL_SUCCESS) { status = NVL_SUCCESS; } if (_nvswitch_service_nvltlc_rx_lnk_fatal_1_ls10(device, nvlipt_instance, i) == NVL_SUCCESS) { status = NVL_SUCCESS; } } FOR_EACH_INDEX_IN_MASK_END; return status; } static NvlStatus _nvswitch_service_nvlipt_common_fatal_ls10 ( nvswitch_device *device, NvU32 instance ) { NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, contain, unhandled; NvU32 link, local_link_idx; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_ENG_RD32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_STATUS_0); report.raw_enable = NVSWITCH_ENG_RD32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable & (DRF_NUM(_NVLIPT_COMMON, _ERR_STATUS_0, _CLKCTL_ILLEGAL_REQUEST, 1)); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } error_event.nvliptInstance = (NvU8) instance; unhandled = pending; report.raw_first = NVSWITCH_ENG_RD32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_FIRST_0); contain = NVSWITCH_ENG_RD32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_CONTAIN_EN_0); bit = DRF_NUM(_NVLIPT_COMMON, _ERR_STATUS_0, _CLKCTL_ILLEGAL_REQUEST, 1); if (nvswitch_test_flags(pending, bit)) { for (local_link_idx = 0; local_link_idx < NVSWITCH_LINKS_PER_NVLIPT_LS10; local_link_idx++) { link = (instance * NVSWITCH_LINKS_PER_NVLIPT_LS10) + local_link_idx; if (nvswitch_is_link_valid(device, link)) { NVSWITCH_REPORT_CONTAIN(_HW_NVLIPT_CLKCTL_ILLEGAL_REQUEST, "CLKCTL_ILLEGAL_REQUEST", NV_FALSE); } } nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_CLKCTL_ILLEGAL_REQUEST_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. for (local_link_idx = 0; local_link_idx < NVSWITCH_LINKS_PER_NVLIPT_LS10; local_link_idx++) { link = (instance * NVSWITCH_LINKS_PER_NVLIPT_LS10) + local_link_idx; if (nvswitch_is_link_valid(device, link) && (device->link[link].fatal_error_occurred)) { NVSWITCH_ENG_WR32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); break; } } // clear the interrupts if (report.raw_first & report.mask) { NVSWITCH_ENG_WR32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_ENG_WR32(device, NVLIPT, , instance, _NVLIPT_COMMON, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLIPT_COMMON FATAL interrupts, pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nxbar_tile_ls10 ( nvswitch_device *device, NvU32 tile ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 link = tile; report.raw_pending = NVSWITCH_TILE_RD32(device, tile, _NXBAR_TILE, _ERR_STATUS); report.raw_enable = NVSWITCH_TILE_RD32(device, tile, _NXBAR_TILE, _ERR_FATAL_INTR_EN); report.mask = chip_device->intr_mask.tile.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_TILE_RD32(device, tile, _NXBAR_TILE, _ERR_FIRST); bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_BUFFER_OVERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_BUFFER_OVERFLOW, "ingress SRC-VC buffer overflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_BUFFER_UNDERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_BUFFER_UNDERFLOW, "ingress SRC-VC buffer underflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _EGRESS_CREDIT_OVERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_EGRESS_CREDIT_OVERFLOW, "egress DST-VC credit overflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _EGRESS_CREDIT_UNDERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_EGRESS_CREDIT_UNDERFLOW, "egress DST-VC credit underflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_NON_BURSTY_PKT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_NON_BURSTY_PKT, "ingress packet burst error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_NON_STICKY_PKT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_NON_STICKY_PKT, "ingress packet sticky error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_BURST_GT_9_DATA_VC, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_BURST_GT_9_DATA_VC, "possible bubbles at ingress", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_PKT_INVALID_DST, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_PKT_INVALID_DST, "ingress packet invalid dst error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILE, _ERR_STATUS, _INGRESS_PKT_PARITY_ERROR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILE_INGRESS_PKT_PARITY_ERROR, "ingress packet parity error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } if (report.raw_first & report.mask) { NVSWITCH_TILE_WR32(device, tile, _NXBAR_TILE, _ERR_FIRST, report.raw_first & report.mask); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. NVSWITCH_TILE_WR32(device, tile, _NXBAR_TILE, _ERR_FATAL_INTR_EN, report.raw_enable ^ pending); NVSWITCH_TILE_WR32(device, link, _NXBAR_TILE, _ERR_STATUS, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nxbar_tileout_ls10 ( nvswitch_device *device, NvU32 tileout ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 link = tileout; report.raw_pending = NVSWITCH_TILEOUT_RD32(device, tileout, _NXBAR_TILEOUT, _ERR_STATUS); report.raw_enable = NVSWITCH_TILEOUT_RD32(device, tileout, _NXBAR_TILEOUT, _ERR_FATAL_INTR_EN); report.mask = chip_device->intr_mask.tileout.fatal; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_TILEOUT_RD32(device, tileout, _NXBAR_TILEOUT, _ERR_FIRST); bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _INGRESS_BUFFER_OVERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_INGRESS_BUFFER_OVERFLOW, "ingress SRC-VC buffer overflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _INGRESS_BUFFER_UNDERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_INGRESS_BUFFER_UNDERFLOW, "ingress SRC-VC buffer underflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _EGRESS_CREDIT_OVERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_EGRESS_CREDIT_OVERFLOW, "egress DST-VC credit overflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _EGRESS_CREDIT_UNDERFLOW, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_EGRESS_CREDIT_UNDERFLOW, "egress DST-VC credit underflow", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _INGRESS_NON_BURSTY_PKT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_INGRESS_NON_BURSTY_PKT, "ingress packet burst error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _INGRESS_NON_STICKY_PKT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_INGRESS_NON_STICKY_PKT, "ingress packet sticky error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _INGRESS_BURST_GT_9_DATA_VC, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_INGRESS_BURST_GT_9_DATA_VC, "possible bubbles at ingress", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NXBAR_TILEOUT, _ERR_STATUS, _EGRESS_CDT_PARITY_ERROR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NXBAR_TILEOUT_EGRESS_CDT_PARITY_ERROR, "ingress credit parity error", NV_TRUE); nvswitch_clear_flags(&unhandled, bit); } if (report.raw_first & report.mask) { NVSWITCH_TILEOUT_WR32(device, tileout, _NXBAR_TILEOUT, _ERR_FIRST, report.raw_first & report.mask); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. // This helps prevent an interrupt storm if HW keeps triggering unnecessary stream of interrupts. NVSWITCH_TILEOUT_WR32(device, tileout, _NXBAR_TILEOUT, _ERR_FATAL_INTR_EN, report.raw_enable ^ pending); NVSWITCH_TILEOUT_WR32(device, tileout, _NXBAR_TILEOUT, _ERR_STATUS, pending); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nxbar_fatal_ls10 ( nvswitch_device *device, NvU32 nxbar ) { NvU32 pending, bit, unhandled; NvU32 tile_idx; NvU32 tile, tileout; pending = NVSWITCH_ENG_RD32(device, NXBAR, , nxbar, _NXBAR, _TCP_ERROR_STATUS); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; for (tile = 0; tile < NUM_NXBAR_TILES_PER_TC_LS10; tile++) { bit = DRF_NUM(_NXBAR, _TCP_ERROR_STATUS, _TILE0, 1) << tile; if (nvswitch_test_flags(pending, bit)) { tile_idx = TILE_INDEX_LS10(device, nxbar, tile); if (NVSWITCH_ENG_VALID_LS10(device, TILE, tile_idx)) { if (_nvswitch_service_nxbar_tile_ls10(device, tile_idx) == NVL_SUCCESS) { nvswitch_clear_flags(&unhandled, bit); } } } } for (tileout = 0; tileout < NUM_NXBAR_TILEOUTS_PER_TC_LS10; tileout++) { bit = DRF_NUM(_NXBAR, _TCP_ERROR_STATUS, _TILEOUT0, 1) << tileout; if (nvswitch_test_flags(pending, bit)) { tile_idx = TILE_INDEX_LS10(device, nxbar, tileout); if (NVSWITCH_ENG_VALID_LS10(device, TILEOUT, tile_idx)) { if (_nvswitch_service_nxbar_tileout_ls10(device, tile_idx) == NVL_SUCCESS) { nvswitch_clear_flags(&unhandled, bit); } } } } // TODO: Perform hot_reset to recover NXBAR NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static void _nvswitch_emit_link_errors_nvldl_fatal_link_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit; INFOROM_NVLINK_ERROR_EVENT error_event; // Only enabled link errors are deffered pending = chip_device->deferredLinkErrors[link].fatalIntrMask.dl; report.raw_pending = pending; report.raw_enable = pending; report.mask = report.raw_enable; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); bit = DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_UP, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_LTSSM_FAULT_UP, "LTSSM Fault Up", NV_FALSE); error_event.error = INFOROM_NVLINK_DL_LTSSM_FAULT_UP_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_DOWN, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_LTSSM_FAULT_DOWN, "LTSSM Fault Down", NV_FALSE); error_event.error = INFOROM_NVLINK_DL_LTSSM_FAULT_DOWN_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } static void _nvswitch_emit_link_errors_minion_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 regData; NvU32 enabledLinks; NvU32 localLinkIdx = NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); NvU32 bit = BIT(localLinkIdx); if (!chip_device->deferredLinkErrors[link].fatalIntrMask.minionLinkIntr.bPending) { return; } // Grab the cached interrupt data regData = chip_device->deferredLinkErrors[link].fatalIntrMask.minionLinkIntr.regData; // get all possible interrupting links associated with this minion report.raw_enable = link; report.raw_pending = report.raw_enable; report.mask = report.raw_enable; report.data[0] = regData; switch(DRF_VAL(_MINION, _NVLINK_LINK_INTR, _CODE, regData)) { case NV_MINION_NVLINK_LINK_INTR_CODE_NA: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link NA interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_DLCMDFAULT: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link DLCMDFAULT interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_NOINIT: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link NOINIT interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_LOCAL_CONFIG_ERR: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link Local-Config-Error interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_NEGOTIATION_CONFIG_ERR: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link Negotiation Config Err Interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_BADINIT: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link BADINIT interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_PMFAIL: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link PMFAIL interrupt", NV_FALSE); break; default: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Interrupt code unknown", NV_FALSE); } // Fatal error was hit so disable the interrupt regData = NVSWITCH_MINION_RD32_LS10(device, nvlipt_instance, _MINION, _MINION_INTR_STALL_EN); enabledLinks = DRF_VAL(_MINION, _MINION_INTR_STALL_EN, _LINK, regData); enabledLinks &= ~bit; regData = DRF_NUM(_MINION, _MINION_INTR_STALL_EN, _LINK, enabledLinks); NVSWITCH_MINION_LINK_WR32_LS10(device, link, _MINION, _MINION_INTR_STALL_EN, regData); } static void _nvswitch_emit_link_errors_minion_nonfatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 regData; NvU32 localLinkIdx = NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); NvU32 bit = BIT(localLinkIdx); if (!chip_device->deferredLinkErrors[link].nonFatalIntrMask.minionLinkIntr.bPending) { return; } // read in the enaled minion interrupts on this minion regData = NVSWITCH_MINION_RD32_LS10(device, nvlipt_instance, _MINION, _MINION_INTR_STALL_EN); // Grab the cached interrupt data regData = chip_device->deferredLinkErrors[link].nonFatalIntrMask.minionLinkIntr.regData; // get all possible interrupting links associated with this minion report.raw_enable = link; report.raw_pending = report.raw_enable; report.mask = report.raw_enable; report.data[0] = regData; switch(DRF_VAL(_MINION, _NVLINK_LINK_INTR, _CODE, regData)) { case NV_MINION_NVLINK_LINK_INTR_CODE_DLREQ: NVSWITCH_REPORT_NONFATAL(_HW_MINION_NONFATAL, "Minion Link DLREQ interrupt"); break; case NV_MINION_NVLINK_LINK_INTR_CODE_PMDISABLED: NVSWITCH_REPORT_NONFATAL(_HW_MINION_NONFATAL, "Minion Link PMDISABLED interrupt"); break; case NV_MINION_NVLINK_LINK_INTR_CODE_DLCMDFAULT: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Link DLCMDFAULT interrupt", NV_FALSE); break; case NV_MINION_NVLINK_LINK_INTR_CODE_TLREQ: NVSWITCH_REPORT_NONFATAL(_HW_MINION_NONFATAL, "Minion Link TLREQ interrupt"); break; } } static void _nvswitch_emit_link_errors_nvldl_nonfatal_link_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, reg; // Only enabled link errors are deffered pending = chip_device->deferredLinkErrors[link].nonFatalIntrMask.dl; report.raw_pending = pending; report.raw_enable = pending; report.mask = report.raw_enable; bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_SHORT_ERROR_RATE, 1); if (nvswitch_test_flags(pending, bit)) { // Disable further interrupts nvlink_link *nvlink = nvswitch_get_link(device, link); if (nvlink == NULL) { // If we get here, it is a bug. Disable interrupt and assert. reg = NVSWITCH_LINK_RD32_LS10(device, link, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN); reg = FLD_SET_DRF_NUM(_NVLDL_TOP, _INTR_NONSTALL_EN, _RX_SHORT_ERROR_RATE, 0, reg); NVSWITCH_LINK_WR32_LS10(device, link, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN, reg); NVSWITCH_ASSERT(nvlink != NULL); } else { nvlink->errorThreshold.bInterruptTrigerred = NV_TRUE; nvswitch_configure_error_rate_threshold_interrupt_ls10(nvlink, NV_FALSE); NVSWITCH_REPORT_NONFATAL(_HW_DLPL_RX_SHORT_ERROR_RATE, "RX Short Error Rate"); } } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_CRC_COUNTER, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_DLPL_RX_CRC_COUNTER, "RX CRC Error Rate"); } } static void _nvswitch_emit_link_errors_nvltlc_rx_lnk_nonfatal_1_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit; INFOROM_NVLINK_ERROR_EVENT error_event; NvU32 injected; // Only enabled link errors are deffered pending = chip_device->deferredLinkErrors[link].nonFatalIntrMask.tlcRx1; injected = chip_device->deferredLinkErrors[link].nonFatalIntrMask.tlcRx1Injected; report.raw_pending = pending; report.raw_enable = pending; report.mask = report.raw_enable; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _HEARTBEAT_TIMEOUT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_RX_LNK_AN1_HEARTBEAT_TIMEOUT_ERR, "AN1 Heartbeat Timeout Error"); if (FLD_TEST_DRF_NUM(_NVLTLC_RX_LNK, _ERR_REPORT_INJECT_1, _HEARTBEAT_TIMEOUT_ERR, 0x0, injected)) { error_event.error = INFOROM_NVLINK_TLC_RX_AN1_HEARTBEAT_TIMEOUT_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } } static void _nvswitch_emit_link_errors_nvlipt_lnk_nonfatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit; INFOROM_NVLINK_ERROR_EVENT error_event; // Only enabled link errors are deffered pending = chip_device->deferredLinkErrors[link].nonFatalIntrMask.liptLnk; report.raw_pending = pending; report.raw_enable = pending; report.mask = report.raw_enable; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _FAILEDMINIONREQUEST, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_FAILEDMINIONREQUEST, "_FAILEDMINIONREQUEST"); { error_event.error = INFOROM_NVLINK_NVLIPT_FAILED_MINION_REQUEST_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } } static void _nvswitch_emit_deferred_link_errors_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { _nvswitch_emit_link_errors_nvldl_fatal_link_ls10(device, nvlipt_instance, link); _nvswitch_emit_link_errors_nvldl_nonfatal_link_ls10(device, link); _nvswitch_emit_link_errors_nvltlc_rx_lnk_nonfatal_1_ls10(device, nvlipt_instance, link); _nvswitch_emit_link_errors_nvlipt_lnk_nonfatal_ls10(device, nvlipt_instance, link); _nvswitch_emit_link_errors_minion_fatal_ls10(device, nvlipt_instance, link); _nvswitch_emit_link_errors_minion_nonfatal_ls10(device, nvlipt_instance, link); } static void _nvswitch_clear_deferred_link_errors_ls10 ( nvswitch_device *device, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVLINK_LINK_ERROR_REPORTING *pLinkErrors; pLinkErrors = &chip_device->deferredLinkErrors[link]; nvswitch_os_memset(pLinkErrors, 0, sizeof(NVLINK_LINK_ERROR_REPORTING)); } static void _nvswitch_deferred_link_state_check_ls10 ( nvswitch_device *device, void *fn_args ) { NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS *pErrorReportParams = (NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS*)fn_args; NvU32 nvlipt_instance = pErrorReportParams->nvlipt_instance; NvU32 link = pErrorReportParams->link; ls10_device *chip_device; nvlink_link *pLink; NvU64 linkState; chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); pLink = nvswitch_get_link(device, pErrorReportParams->link); // If is there a retry for reset_and_drain then re-create the state check for the current link if (chip_device->deferredLinkErrors[link].bResetAndDrainRetry == NV_TRUE) { if (pErrorReportParams) { nvswitch_os_free(pErrorReportParams); } chip_device->deferredLinkErrors[link].bLinkErrorsCallBackEnabled = NV_FALSE; chip_device->deferredLinkErrors[link].bResetAndDrainRetry = NV_FALSE; nvswitch_create_deferred_link_state_check_task_ls10(device, nvlipt_instance, link); return; } if ((pLink == NULL) || (device->hal.nvswitch_corelib_get_dl_link_mode(pLink, &linkState) != NVL_SUCCESS) || ((linkState != NVLINK_LINKSTATE_HS) && (linkState != NVLINK_LINKSTATE_SLEEP))) { _nvswitch_emit_deferred_link_errors_ls10(device, nvlipt_instance, link); } _nvswitch_clear_deferred_link_errors_ls10(device, link); nvswitch_os_free(pErrorReportParams); chip_device->deferredLinkErrors[link].bLinkStateCallBackEnabled = NV_FALSE; } void nvswitch_create_deferred_link_state_check_task_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS *pErrorReportParams; NvlStatus status; if (chip_device->deferredLinkErrors[link].bLinkStateCallBackEnabled) { return; } status = NVL_ERR_GENERIC; pErrorReportParams = nvswitch_os_malloc(sizeof(NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS)); if(pErrorReportParams != NULL) { pErrorReportParams->nvlipt_instance = nvlipt_instance; pErrorReportParams->link = link; status = nvswitch_task_create_args(device, (void*)pErrorReportParams, &_nvswitch_deferred_link_state_check_ls10, NVSWITCH_DEFERRED_LINK_STATE_CHECK_INTERVAL_NS, NVSWITCH_TASK_TYPE_FLAGS_RUN_ONCE | NVSWITCH_TASK_TYPE_FLAGS_VOID_PTR_ARGS); } if (status == NVL_SUCCESS) { chip_device->deferredLinkErrors[link].bLinkStateCallBackEnabled = NV_TRUE; } else { NVSWITCH_PRINT(device, ERROR, "%s: Failed to allocate memory. Cannot defer link state check.\n", __FUNCTION__); _nvswitch_emit_deferred_link_errors_ls10(device, nvlipt_instance, link); _nvswitch_clear_deferred_link_errors_ls10(device, link); nvswitch_os_free(pErrorReportParams); } } static void _nvswitch_deferred_link_errors_check_ls10 ( nvswitch_device *device, void *fn_args ) { NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS *pErrorReportParams = (NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS*)fn_args; NvU32 nvlipt_instance = pErrorReportParams->nvlipt_instance; NvU32 link = pErrorReportParams->link; ls10_device *chip_device; NvU32 pending; chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); pending = chip_device->deferredLinkErrors[link].fatalIntrMask.dl; if (FLD_TEST_DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_UP, 1U, pending) || FLD_TEST_DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_DOWN, 1U, pending) ) { nvswitch_create_deferred_link_state_check_task_ls10(device, nvlipt_instance, link); } else { _nvswitch_emit_deferred_link_errors_ls10(device, nvlipt_instance, link); _nvswitch_clear_deferred_link_errors_ls10(device, link); } if (pErrorReportParams) { nvswitch_os_free(pErrorReportParams); } chip_device->deferredLinkErrors[link].bLinkErrorsCallBackEnabled = NV_FALSE; } static void _nvswitch_create_deferred_link_errors_task_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS *pErrorReportParams; NvlStatus status; if (chip_device->deferredLinkErrors[link].bLinkErrorsCallBackEnabled) { return; } chip_device->deferredLinkErrors[link].bResetAndDrainRetry = NV_FALSE; status = NVL_ERR_GENERIC; pErrorReportParams = nvswitch_os_malloc(sizeof(NVSWITCH_DEFERRED_ERROR_REPORTING_ARGS)); if(pErrorReportParams != NULL) { pErrorReportParams->nvlipt_instance = nvlipt_instance; pErrorReportParams->link = link; status = nvswitch_task_create_args(device, (void*)pErrorReportParams, &_nvswitch_deferred_link_errors_check_ls10, NVSWITCH_DEFERRED_FAULT_UP_CHECK_INTERVAL_NS, NVSWITCH_TASK_TYPE_FLAGS_RUN_ONCE | NVSWITCH_TASK_TYPE_FLAGS_VOID_PTR_ARGS); } if (status == NVL_SUCCESS) { chip_device->deferredLinkErrors[link].bLinkErrorsCallBackEnabled = NV_TRUE; } else { NVSWITCH_PRINT(device, ERROR, "%s: Failed to create task. Cannot defer link error check.\n", __FUNCTION__); _nvswitch_emit_deferred_link_errors_ls10(device, nvlipt_instance, link); _nvswitch_clear_deferred_link_errors_ls10(device, link); nvswitch_os_free(pErrorReportParams); } } static NvlStatus _nvswitch_service_nvldl_nonfatal_link_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLDL, _NVLDL_TOP, _INTR); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_REPLAY, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_DLPL_TX_REPLAY, "TX Replay Error"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_RECOVERY_SHORT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_DLPL_TX_RECOVERY_SHORT, "TX Recovery Short"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_SHORT_ERROR_RATE, 1); if (nvswitch_test_flags(pending, bit)) { chip_device->deferredLinkErrors[link].nonFatalIntrMask.dl |= bit; _nvswitch_create_deferred_link_errors_task_ls10(device, nvlipt_instance, link); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_LONG_ERROR_RATE, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_DLPL_RX_LONG_ERROR_RATE, "RX Long Error Rate"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_ILA_TRIGGER, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_DLPL_RX_ILA_TRIGGER, "RX ILA Trigger"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_CRC_COUNTER, 1); if (nvswitch_test_flags(pending, bit)) { chip_device->deferredLinkErrors[link].nonFatalIntrMask.dl |= bit; _nvswitch_create_deferred_link_errors_task_ls10(device, nvlipt_instance, link); nvswitch_clear_flags(&unhandled, bit); // // Mask CRC counter after first occurrance - otherwise, this interrupt // will continue to fire once the CRC counter has hit the threshold // See Bug 3341528 // report.raw_enable = report.raw_enable & (~bit); NVSWITCH_LINK_WR32(device, link, NVLDL, _NVLDL_TOP, _INTR_NONSTALL_EN, report.raw_enable); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); NVSWITCH_LINK_WR32(device, link, NVLDL, _NVLDL_TOP, _INTR, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLDL nonfatal interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvldl_nonfatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU64 intrLinkMask ) { NvU64 localLinkMask, enabledLinkMask, localIntrLinkMask; NvU32 i; nvlink_link *link; NvlStatus status; NvlStatus return_status = -NVL_NOT_FOUND; NvU32 clocksMask = NVSWITCH_PER_LINK_CLOCK_SET(RXCLK) | NVSWITCH_PER_LINK_CLOCK_SET(TXCLK); // // The passed in interruptLinkMask should contain a link that is part of the // given nvlipt instance // localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(nvlipt_instance); enabledLinkMask = nvswitch_get_enabled_link_mask(device); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { link = nvswitch_get_link(device, i); if (link == NULL) { // An interrupt on an invalid link should never occur NVSWITCH_ASSERT(link != NULL); continue; } if (NVSWITCH_GET_LINK_ENG_INST(device, i, NVLIPT) != nvlipt_instance) { NVSWITCH_ASSERT(0); break; } if (nvswitch_is_link_in_reset(device, link) || !nvswitch_are_link_clocks_on_ls10(device, link, clocksMask)) { continue; } status = _nvswitch_service_nvldl_nonfatal_link_ls10(device, nvlipt_instance, i); if (status != NVL_SUCCESS) { return_status = status; } } FOR_EACH_INDEX_IN_MASK_END; return return_status; } static NvlStatus _nvswitch_service_nvltlc_rx_lnk_nonfatal_0_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_0, _RXRSPSTATUS_PRIV_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_RX_LNK_RXRSPSTATUS_PRIV_ERR, "RX Rsp Status PRIV Error"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_RX_RSP_STATUS_PRIV_ERR_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_RX_LNK _0 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_tx_lnk_nonfatal_0_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _CREQ_RAM_DAT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_CREQ_RAM_DAT_ECC_DBE_ERR, "CREQ RAM DAT ECC DBE Error"); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_TX_CREQ_DAT_RAM_ECC_DBE_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _CREQ_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_CREQ_RAM_ECC_LIMIT_ERR, "CREQ RAM DAT ECC Limit Error"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP_RAM_DAT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_RSP_RAM_DAT_ECC_DBE_ERR, "Response RAM DAT ECC DBE Error"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_RSP_RAM_ECC_LIMIT_ERR, "Response RAM ECC Limit Error"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _COM_RAM_DAT_ECC_DBE_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_COM_RAM_DAT_ECC_DBE_ERR, "COM RAM DAT ECC DBE Error"); nvswitch_clear_flags(&unhandled, bit); { // TODO 3014908 log these in the NVL object until we have ECC object support error_event.error = INFOROM_NVLINK_TLC_TX_COM_DAT_RAM_ECC_DBE_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _COM_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_COM_RAM_ECC_LIMIT_ERR, "COM RAM ECC Limit Error"); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_0, _RSP1_RAM_ECC_LIMIT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_RSP1_RAM_ECC_LIMIT_ERR, "RSP1 RAM ECC Limit Error"); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_NON_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_TX_LNK _0 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_rx_lnk_nonfatal_1_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 injected; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_1); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_NON_FATAL_REPORT_EN_1); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_1); injected = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_REPORT_INJECT_1); bit = DRF_NUM(_NVLTLC_RX_LNK, _ERR_STATUS_1, _HEARTBEAT_TIMEOUT_ERR, 1); if (nvswitch_test_flags(pending, bit)) { chip_device->deferredLinkErrors[link].nonFatalIntrMask.tlcRx1 |= bit; chip_device->deferredLinkErrors[link].nonFatalIntrMask.tlcRx1Injected |= injected; _nvswitch_create_deferred_link_errors_task_ls10(device, nvlipt_instance, link); if (FLD_TEST_DRF_NUM(_NVLTLC_RX_LNK, _ERR_REPORT_INJECT_1, _HEARTBEAT_TIMEOUT_ERR, 0x0, injected)) { // // WAR Bug 200627368: Mask off HBTO to avoid a storm // During the start of reset_and_drain, all links on the GPU // will go into contain, causing HBTO on other switch links connected // to that GPU. For the switch side, these interrupts are not fatal, // but until we get to reset_and_drain for this link, HBTO will continue // to fire repeatedly. After reset_and_drain, HBTO will be re-enabled // by MINION after links are trained. // report.raw_enable = report.raw_enable & (~bit); NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_NON_FATAL_REPORT_EN_1, report.raw_enable); } nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_NON_FATAL_REPORT_EN_1, report.raw_enable & (~pending)); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_RX_LNK, _ERR_STATUS_1, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_RX_LNK _1 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_tx_lnk_nonfatal_1_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NvU32 pending, bit, unhandled; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_1); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_NON_FATAL_REPORT_EN_1); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_1); bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC0, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC0, "AN1 Timeout VC0"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC0_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC1, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC1, "AN1 Timeout VC1"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC1_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC2, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC2, "AN1 Timeout VC2"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC2_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC3, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC3, "AN1 Timeout VC3"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC3_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC4, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC4, "AN1 Timeout VC4"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC4_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC5, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC5, "AN1 Timeout VC5"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC5_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC6, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC6, "AN1 Timeout VC6"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC6_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLTLC_TX_LNK, _ERR_STATUS_1, _TIMEOUT_VC7, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLTLC_TX_LNK_AN1_TIMEOUT_VC7, "AN1 Timeout VC7"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC7_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_NON_FATAL_REPORT_EN_1, report.raw_enable ^ pending); } if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_FIRST_1, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLTLC, _NVLTLC_TX_LNK, _ERR_STATUS_1, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLTLC_TX_LNK _1 interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvltlc_nonfatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU64 intrLinkMask ) { NvU64 localLinkMask, enabledLinkMask, localIntrLinkMask; NvU32 i; nvlink_link *link; NvlStatus status; NvlStatus return_status = NVL_SUCCESS; localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(nvlipt_instance); enabledLinkMask = nvswitch_get_enabled_link_mask(device); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { link = nvswitch_get_link(device, i); if (link == NULL) { // An interrupt on an invalid link should never occur NVSWITCH_ASSERT(link != NULL); continue; } if (NVSWITCH_GET_LINK_ENG_INST(device, i, NVLIPT) != nvlipt_instance) { NVSWITCH_ASSERT(0); break; } // // If link is in reset or NCISOC clock is off then // don't need to check the link for NVLTLC errors // as the IP's registers are off // if (nvswitch_is_link_in_reset(device, link) || !nvswitch_are_link_clocks_on_ls10(device, link, NVSWITCH_PER_LINK_CLOCK_SET(NCISOCCLK))) { continue; } status = _nvswitch_service_nvltlc_rx_lnk_nonfatal_0_ls10(device, nvlipt_instance, i); if (status != NVL_SUCCESS) { return_status = status; } status = _nvswitch_service_nvltlc_tx_lnk_nonfatal_0_ls10(device, nvlipt_instance, i); if (status != NVL_SUCCESS) { return_status = status; } status = _nvswitch_service_nvltlc_rx_lnk_nonfatal_1_ls10(device, nvlipt_instance, i); if (status != NVL_SUCCESS) { return_status = status; } status = _nvswitch_service_nvltlc_tx_lnk_nonfatal_1_ls10(device, nvlipt_instance, i); if (status != NVL_SUCCESS) { return_status = status; } } FOR_EACH_INDEX_IN_MASK_END; return return_status; } static NvlStatus _nvswitch_service_nvlipt_lnk_status_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link_id ) { NvU32 pending, enabled, unhandled, bit; NvU64 mode; nvlink_link *link; link = nvswitch_get_link(device, link_id); pending = NVSWITCH_LINK_RD32(device, link_id, NVLIPT_LNK, _NVLIPT_LNK, _INTR_STATUS); enabled = NVSWITCH_LINK_RD32(device, link_id, NVLIPT_LNK, _NVLIPT_LNK, _INTR_INT1_EN); pending &= enabled; unhandled = pending; bit = DRF_NUM(_NVLIPT_LNK, _INTR_STATUS, _LINKSTATEREQUESTREADYSET, 1); if (nvswitch_test_flags(pending, bit)) { link = nvswitch_get_link(device, link_id); if (link == NULL) { // If we get here, it's a bug. Assert, then let callers detect unhandled IRQ. NVSWITCH_ASSERT(link != NULL); } nvswitch_clear_flags(&unhandled, bit); if(nvswitch_corelib_get_dl_link_mode_ls10(link, &mode) != NVL_SUCCESS) { NVSWITCH_PRINT(device, ERROR, "%s: nvlipt_lnk_status: Failed to check link mode! LinkId %d\n", __FUNCTION__, link_id); } else if(mode == NVLINK_LINKSTATE_HS) { NVSWITCH_PRINT(device, INFO, "%s: nvlipt_lnk_status: Link is up!. LinkId %d\n", __FUNCTION__, link_id); if (nvswitch_lib_notify_client_events(device, NVSWITCH_DEVICE_EVENT_PORT_UP) != NVL_SUCCESS) { NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify PORT_UP event. LinkId %d\n", __FUNCTION__, link_id); } // // When a link comes up ensure that we finish off the post-training tasks: // -- enabling per-link DL interrupts // -- releasing buffer_ready on the link // nvswitch_corelib_training_complete_ls10(link); nvswitch_init_buffer_ready(device, link, NV_TRUE); link->bRxDetected = NV_TRUE; } else if (mode == NVLINK_LINKSTATE_FAULT) { // // If we are here then a previous state transition caused // the link to FAULT as there is no TL Link state requests // that explicitly transitions a link to fault. If that is the // case, set the DL interrupts so any errors can be handled // nvswitch_set_dlpl_interrupts_ls10(link); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); NVSWITCH_LINK_WR32(device, link_id, NVLIPT_LNK, _NVLIPT_LNK, _INTR_STATUS, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLIPT_LNK STATUS interrupts, pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, pending, enabled); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvlipt_lnk_nonfatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); nvlink_link *link_info = nvswitch_get_link(device, link); NvU32 lnkStateRequest, linkState; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_NON_FATAL_REPORT_EN_0); report.mask = report.raw_enable; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _ILLEGALLINKSTATEREQUEST, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_ILLEGALLINKSTATEREQUEST, "_HW_NVLIPT_LNK_ILLEGALLINKSTATEREQUEST"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_ILLEGAL_LINK_STATE_REQUEST_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _FAILEDMINIONREQUEST, 1); if (nvswitch_test_flags(pending, bit)) { // // Read back LINK_STATE_REQUESTS and TOP_LINK_STATE registers // If request == ACTIVE and TOP_LINK_STATE == FAULT there is a pending // fault on training so re-run reset_and_drain // Mark that the defered link error mechanism as seeing a reset_and_train re-try so // the deferred task needs to re-create itself instead of continuing with the linkstate // checks // linkState = NVSWITCH_LINK_RD32_LS10(device, link_info->linkNumber, NVLDL, _NVLDL, _TOP_LINK_STATE); lnkStateRequest = NVSWITCH_LINK_RD32_LS10(device, link, NVLIPT_LNK , _NVLIPT_LNK , _CTRL_LINK_STATE_REQUEST); if(FLD_TEST_DRF(_NVLIPT_LNK, _CTRL_LINK_STATE_REQUEST, _REQUEST, _ACTIVE, lnkStateRequest) && linkState == NV_NVLDL_TOP_LINK_STATE_STATE_FAULT) { chip_device->deferredLinkErrors[link].bResetAndDrainRetry = NV_TRUE; device->hal.nvswitch_reset_and_drain_links(device, NVBIT64(link)); } chip_device->deferredLinkErrors[link].nonFatalIntrMask.liptLnk |= bit; _nvswitch_create_deferred_link_errors_task_ls10(device, nvlipt_instance, link); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _RESERVEDREQUESTVALUE, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_RESERVEDREQUESTVALUE, "_RESERVEDREQUESTVALUE"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_RESERVED_REQUEST_VALUE_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _LINKSTATEWRITEWHILEBUSY, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_LINKSTATEWRITEWHILEBUSY, "_LINKSTATEWRITEWHILEBUSY"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_LINK_STATE_WRITE_WHILE_BUSY_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _LINK_STATE_REQUEST_TIMEOUT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_LINK_STATE_REQUEST_TIMEOUT, "_LINK_STATE_REQUEST_TIMEOUT"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_LINK_STATE_REQUEST_TIMEOUT_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _WRITE_TO_LOCKED_SYSTEM_REG_ERR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_NONFATAL(_HW_NVLIPT_LNK_WRITE_TO_LOCKED_SYSTEM_REG_ERR, "_WRITE_TO_LOCKED_SYSTEM_REG_ERR"); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_WRITE_TO_LOCKED_SYSTEM_REG_NONFATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLIPT_LNK NON_FATAL interrupts, pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvlipt_link_nonfatal_ls10 ( nvswitch_device *device, NvU32 instance, NvU64 intrLinkMask ) { NvU32 i, intrLink; NvU64 localLinkMask, enabledLinkMask, localIntrLinkMask; NvU64 interruptingLinks = 0; NvU64 lnkStatusChangeLinks = 0; NvlStatus status = NVL_SUCCESS; NvlStatus retStatus = NVL_SUCCESS; // // The passed in interruptLinkMask should contain a link that is part of the // given nvlipt instance // localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(instance); enabledLinkMask = nvswitch_get_enabled_link_mask(device); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { if (NVSWITCH_GET_LINK_ENG_INST(device, i, NVLIPT) != instance) { NVSWITCH_ASSERT(0); break; } intrLink = NVSWITCH_LINK_RD32(device, i, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0); if(intrLink) { interruptingLinks |= NVBIT64(i); } intrLink = NVSWITCH_LINK_RD32(device, i, NVLIPT_LNK, _NVLIPT_LNK, _INTR_STATUS); if(intrLink) { lnkStatusChangeLinks |= NVBIT64(i); } } FOR_EACH_INDEX_IN_MASK_END; FOR_EACH_INDEX_IN_MASK(64, i, lnkStatusChangeLinks) { if(_nvswitch_service_nvlipt_lnk_status_ls10(device, instance, i) != NVL_SUCCESS) { NVSWITCH_PRINT(device, WARN, "%s: Could not process nvlipt link status interrupt. Continuing. LinkId %d\n", __FUNCTION__, i); } } FOR_EACH_INDEX_IN_MASK_END; FOR_EACH_INDEX_IN_MASK(64, i, interruptingLinks) { status = _nvswitch_service_nvlipt_lnk_nonfatal_ls10(device, instance, i); if (status != NVL_SUCCESS && status != -NVL_NOT_FOUND) { retStatus = -NVL_MORE_PROCESSING_REQUIRED; } } FOR_EACH_INDEX_IN_MASK_END; return retStatus; } NvlStatus _nvswitch_service_minion_fatal_ls10 ( nvswitch_device *device, NvU32 instance ) { NvU32 pending, bit, unhandled, mask; pending = NVSWITCH_MINION_RD32_LS10(device, instance, _MINION, _MINION_INTR); mask = NVSWITCH_MINION_RD32_LS10(device, instance, _MINION, _MINION_INTR_STALL_EN); // Don't consider MINION Link interrupts in this handler mask &= ~(DRF_NUM(_MINION, _MINION_INTR_STALL_EN, _LINK, NV_MINION_MINION_INTR_STALL_EN_LINK_ENABLE_ALL)); pending &= mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; bit = DRF_NUM(_MINION, _MINION_INTR, _FALCON_STALL, 0x1); if (nvswitch_test_flags(pending, bit)) { if (nvswitch_minion_service_falcon_interrupts_ls10(device, instance) == NVL_SUCCESS) { nvswitch_clear_flags(&unhandled, bit); } } bit = DRF_NUM(_MINION, _MINION_INTR, _NONFATAL, 0x1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_PRINT(device, ERROR, "%s: servicing minion nonfatal interrupt\n", __FUNCTION__); NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _MINION_INTR, bit); nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_MINION, _MINION_INTR, _FATAL, 0x1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_PRINT(device, ERROR, "%s: servicing minion fatal interrupt\n", __FUNCTION__); NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _MINION_INTR, bit); nvswitch_clear_flags(&unhandled, bit); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvlw_nonfatal_ls10 ( nvswitch_device *device, NvU32 instance ) { NvlStatus status[3]; NvU32 reg; NvU64 intrLinkMask = 0; reg = NVSWITCH_ENG_RD32_LS10(device, NVLW, instance, _NVLW, _TOP_INTR_1_STATUS); intrLinkMask = DRF_VAL(_NVLW, _TOP_INTR_1_STATUS, _LINK, reg); // // Shift the mask of interrupting links from the local to the // NVLW instance to a global mask // intrLinkMask = intrLinkMask << (NVSWITCH_LINKS_PER_NVLW_LS10*instance); // If there is no pending link interrupts then there is nothing to service if (intrLinkMask == 0) { return NVL_SUCCESS; } status[0] = _nvswitch_service_nvldl_nonfatal_ls10(device, instance, intrLinkMask); status[1] = _nvswitch_service_nvltlc_nonfatal_ls10(device, instance, intrLinkMask); status[2] = _nvswitch_service_nvlipt_link_nonfatal_ls10(device, instance, intrLinkMask); if ((status[0] != NVL_SUCCESS) && (status[0] != -NVL_NOT_FOUND) && (status[1] != NVL_SUCCESS) && (status[1] != -NVL_NOT_FOUND) && (status[2] != NVL_SUCCESS) && (status[2] != -NVL_NOT_FOUND)) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_soe_fatal_ls10 ( nvswitch_device *device ) { // We only support 1 SOE as of LS10. if (soeService_HAL(device, (PSOE)device->pSoe) != NVL_SUCCESS) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvlipt_lnk_fatal_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, bit, unhandled; INFOROM_NVLINK_ERROR_EVENT error_event = { 0 }; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FATAL_REPORT_EN_0); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); unhandled = pending; report.raw_first = NVSWITCH_LINK_RD32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FIRST_0); bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _SLEEPWHILEACTIVELINK, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLIPT_LNK_SLEEPWHILEACTIVELINK, "No non-empty link is detected", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_SLEEP_WHILE_ACTIVE_LINK_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _RSTSEQ_PHYCTL_TIMEOUT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLIPT_LNK_RSTSEQ_PHYCTL_TIMEOUT, "Reset sequencer timed out waiting for a handshake from PHYCTL", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_RSTSEQ_PHYCTL_TIMEOUT_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } bit = DRF_NUM(_NVLIPT_LNK, _ERR_STATUS_0, _RSTSEQ_CLKCTL_TIMEOUT, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_NVLIPT_LNK_RSTSEQ_CLKCTL_TIMEOUT, "Reset sequencer timed out waiting for a handshake from CLKCTL", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); { error_event.error = INFOROM_NVLINK_NVLIPT_RSTSEQ_CLKCTL_TIMEOUT_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FATAL_REPORT_EN_0, report.raw_enable ^ pending); } // clear interrupts if (report.raw_first & report.mask) { NVSWITCH_LINK_WR32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_FIRST_0, report.raw_first & report.mask); } NVSWITCH_LINK_WR32(device, link, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0, pending); if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLIPT_LNK FATAL interrupts, pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } static NvlStatus _nvswitch_service_nvlipt_link_fatal_ls10 ( nvswitch_device *device, NvU32 instance, NvU64 intrLinkMask ) { NvU32 i, intrLink; NvU64 localLinkMask, enabledLinkMask, localIntrLinkMask; NvlStatus status = NVL_SUCCESS; // // The passed in interruptLinkMask should contain a link that is part of the // given nvlipt instance // localLinkMask = NVSWITCH_NVLIPT_GET_LOCAL_LINK_MASK64_LS10(instance); enabledLinkMask = nvswitch_get_enabled_link_mask(device); localIntrLinkMask = localLinkMask & intrLinkMask & enabledLinkMask; if (localIntrLinkMask == 0) { NVSWITCH_PRINT(device, ERROR, "%s: Bad link mask provided for link interrupt servicing!\n", __FUNCTION__); NVSWITCH_ASSERT(0); return -NVL_BAD_ARGS; } // read in error status of current link FOR_EACH_INDEX_IN_MASK(64, i, localIntrLinkMask) { intrLink = NVSWITCH_LINK_RD32(device, i, NVLIPT_LNK, _NVLIPT_LNK, _ERR_STATUS_0); if (intrLink != 0) { if( _nvswitch_service_nvlipt_lnk_fatal_ls10(device, instance, i) != NVL_SUCCESS) { status = -NVL_MORE_PROCESSING_REQUIRED; } } } FOR_EACH_INDEX_IN_MASK_END; return status; } static NvlStatus _nvswitch_service_nvlw_fatal_ls10 ( nvswitch_device *device, NvU32 instance ) { NvlStatus status[6]; NvU64 intrLinkMask = 0; NvU32 reg; reg = NVSWITCH_ENG_RD32_LS10(device, NVLW, instance, _NVLW, _TOP_INTR_0_STATUS); intrLinkMask = DRF_VAL(_NVLW, _TOP_INTR_0_STATUS, _LINK, reg); // // Shift the mask of interrupting links from the local to the // NVLW instance to a global mask // intrLinkMask = intrLinkMask << (NVSWITCH_LINKS_PER_NVLW_LS10*instance); status[0] = device->hal.nvswitch_service_minion_link(device, instance); status[1] = _nvswitch_service_minion_fatal_ls10(device, instance); status[2] = _nvswitch_service_nvlipt_common_fatal_ls10(device, instance); // // If there is a pending link interrupt on this nvlw instance then service // those interrupts in the handlers below. Otherwise, mark the status's // as success as there is nothing to service // if (intrLinkMask != 0) { status[3] = _nvswitch_service_nvldl_fatal_ls10(device, instance, intrLinkMask); status[4] = _nvswitch_service_nvltlc_fatal_ls10(device, instance, intrLinkMask); status[5] = _nvswitch_service_nvlipt_link_fatal_ls10(device, instance, intrLinkMask); } else { status[3] = NVL_SUCCESS; status[4] = NVL_SUCCESS; status[5] = NVL_SUCCESS; } if (status[0] != NVL_SUCCESS && status[0] != -NVL_NOT_FOUND && status[1] != NVL_SUCCESS && status[1] != -NVL_NOT_FOUND && status[2] != NVL_SUCCESS && status[2] != -NVL_NOT_FOUND && status[3] != NVL_SUCCESS && status[3] != -NVL_NOT_FOUND && status[4] != NVL_SUCCESS && status[4] != -NVL_NOT_FOUND && status[5] != NVL_SUCCESS && status[5] != -NVL_NOT_FOUND) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } /* * @Brief : Enable top level HW interrupts. * * @Description : * * @param[in] device operate on this device */ void nvswitch_lib_enable_interrupts_ls10 ( nvswitch_device *device ) { NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NPG_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NPG_NON_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NPG_CORRECTABLE_IDX), 0); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NVLW_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NVLW_NON_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NVLW_CORRECTABLE_IDX), 0); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_NXBAR_FATAL_IDX), 0x7); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_UNITS_IDX), 0xFFFFFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_SET(NV_CTRL_CPU_INTR_UNITS_IDX), DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PMGR_HOST, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER_ALARM, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _SEC0_INTR0_0, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XTL_CPU, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XAL_EP, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PRIV_RING, 1)); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_TOP_EN_SET(0), 0xFFFFFFFF); } /* * @Brief : Disable top level HW interrupts. * * @Description : * * @param[in] device operate on this device */ void nvswitch_lib_disable_interrupts_ls10 ( nvswitch_device *device ) { NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NPG_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NPG_NON_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NPG_CORRECTABLE_IDX), 0); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NVLW_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NVLW_NON_FATAL_IDX), 0xFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NVLW_CORRECTABLE_IDX), 0); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NXBAR_FATAL_IDX), 0x7); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_UNITS_IDX), DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PMGR_HOST, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER_ALARM, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _SEC0_INTR0_0, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XTL_CPU, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XAL_EP, 1) | DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PRIV_RING, 1)); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_TOP_EN_CLEAR(0), 0xFFFFFFFF); } // // Check if there are interrupts pending. // // On silicon/emulation we only use MSIs which are not shared, so this // function does not need to be called. // NvlStatus nvswitch_lib_check_interrupts_ls10 ( nvswitch_device *device ) { NvlStatus retval = NVL_SUCCESS; NvU32 val; val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_TOP(0)); if (DRF_NUM(_CTRL, _CPU_INTR_TOP, _VALUE, val) != 0) { retval = -NVL_MORE_PROCESSING_REQUIRED; } return retval; } static void _nvswitch_retrigger_engine_intr_ls10 ( nvswitch_device *device ) { // re-trigger engine to gin interrupts for CPR and NPG on the FATAL and NONFATAL trees NVSWITCH_BCAST_WR32_LS10(device, CPR, _CPR_SYS, _INTR_RETRIGGER(0), 1); NVSWITCH_BCAST_WR32_LS10(device, CPR, _CPR_SYS, _INTR_RETRIGGER(1), 1); NVSWITCH_BCAST_WR32_LS10(device, NPG, _NPG, _INTR_RETRIGGER(0), 1); NVSWITCH_BCAST_WR32_LS10(device, NPG, _NPG, _INTR_RETRIGGER(1), 1); } void nvswitch_service_minion_all_links_ls10 ( nvswitch_device *device ) { NvU32 val, i; // Check NVLW val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NVLW_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NVLW_FATAL, _MASK, val); if (val != 0) { NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NVLW_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NVLW_FATAL_MASK); i++) { if (val & NVBIT(i)) (void)_nvswitch_service_nvlw_fatal_ls10(device, i); } } } // // Service interrupt and re-enable interrupts. Interrupts should disabled when // this is called. // NvlStatus nvswitch_lib_service_interrupts_ls10 ( nvswitch_device *device ) { NvlStatus status = NVL_SUCCESS; NvlStatus return_status = NVL_SUCCESS; NvU32 val; NvU32 i; // // Interrupt handler steps: // 1. Read Leaf interrupt // 2. Clear leaf interrupt // 3. Run leaf specific interrupt handler // val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NVLW_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NVLW_FATAL, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, INFO, "%s: NVLW FATAL interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NVLW_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NVLW_FATAL_MASK); i++) { if (val & NVBIT(i)) { status = _nvswitch_service_nvlw_fatal_ls10(device, i); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, INFO, "%s: NVLW[%d] FATAL interrupt handling status = %d\n", __FUNCTION__, i, status); return_status = status; } } } } val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NVLW_NON_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NVLW_NON_FATAL, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, INFO, "%s: NVLW NON_FATAL interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NVLW_NON_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NVLW_NON_FATAL_MASK); i++) { if (val & NVBIT(i)) { status = _nvswitch_service_nvlw_nonfatal_ls10(device, i); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, INFO, "%s: NVLW[%d] NON_FATAL interrupt handling status = %d\n", __FUNCTION__, i, status); return_status = status; } } } } val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NVLW_CORRECTABLE); val = DRF_NUM(_CTRL, _CPU_INTR_NVLW_CORRECTABLE, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, ERROR, "%s: NVLW CORRECTABLE interrupts pending = 0x%x\n", __FUNCTION__, val); return_status = -NVL_MORE_PROCESSING_REQUIRED; } // Check NPG val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NPG_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NPG_FATAL, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, INFO, "%s: NPG FATAL interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NPG_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NPG_FATAL_MASK); i++) { if (val & NVBIT(i)) { status = _nvswitch_service_npg_fatal_ls10(device, i); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, INFO, "%s: NPG[%d] FATAL interrupt handling status = %d\n", __FUNCTION__, i, status); return_status = status; } } } } val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NPG_NON_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NPG_NON_FATAL, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, INFO, "%s: NPG NON_FATAL interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NPG_NON_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NPG_NON_FATAL_MASK); i++) { if (val & NVBIT(i)) { status = _nvswitch_service_npg_nonfatal_ls10(device, i); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, INFO, "%s: NPG[%d] NON_FATAL interrupt handling status = %d\n", __FUNCTION__, i, status); return_status = status; } } } } val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NPG_CORRECTABLE); val = DRF_NUM(_CTRL, _CPU_INTR_NPG_CORRECTABLE, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, ERROR, "%s: NPG CORRECTABLE interrupts pending = 0x%x\n", __FUNCTION__, val); return_status = -NVL_MORE_PROCESSING_REQUIRED; } // Check NXBAR val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_NXBAR_FATAL); val = DRF_NUM(_CTRL, _CPU_INTR_NXBAR_FATAL, _MASK, val); if (val != 0) { NVSWITCH_PRINT(device, INFO, "%s: NXBAR FATAL interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_NXBAR_FATAL_IDX), val); for (i = 0; i < DRF_SIZE(NV_CTRL_CPU_INTR_NXBAR_FATAL_MASK); i++) { if (val & NVBIT(i)) { status = _nvswitch_service_nxbar_fatal_ls10(device, i); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, INFO, "%s: NXBAR[%d] FATAL interrupt handling status = %d\n", __FUNCTION__, i, status); return_status = status; } } } } // Check UNITS val = NVSWITCH_ENG_RD32(device, GIN, , 0, _CTRL, _CPU_INTR_UNITS); if (val != 0) { NVSWITCH_PRINT(device, MMIO, "%s: UNIT interrupts pending = 0x%x\n", __FUNCTION__, val); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF(NV_CTRL_CPU_INTR_UNITS_IDX), val); if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PMGR_HOST, 1, val)) { NVSWITCH_PRINT(device, ERROR, "%s: _PMGR_HOST interrupt pending\n", __FUNCTION__); return_status = -NVL_MORE_PROCESSING_REQUIRED; } if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER, 1, val)) { NVSWITCH_PRINT(device, ERROR, "%s: _PTIMER interrupt pending\n", __FUNCTION__); return_status = -NVL_MORE_PROCESSING_REQUIRED; } if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PTIMER_ALARM, 1, val)) { NVSWITCH_PRINT(device, ERROR, "%s: _PTIMER_ALARM interrupt pending\n", __FUNCTION__); return_status = -NVL_MORE_PROCESSING_REQUIRED; } if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XTL_CPU, 1, val)) { NVSWITCH_PRINT(device, ERROR, "%s: _XTL_CPU interrupt pending\n", __FUNCTION__); return_status = -NVL_MORE_PROCESSING_REQUIRED; } if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _XAL_EP, 1, val)) { NVSWITCH_PRINT(device, ERROR, "%s: _XAL_EP interrupt pending\n", __FUNCTION__); return_status = -NVL_MORE_PROCESSING_REQUIRED; } if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _PRIV_RING, 1, val)) { status = _nvswitch_service_priv_ring_ls10(device); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, ERROR, "%s: Problem handling PRI errors\n", __FUNCTION__); return_status = status; } } if (!IS_RTLSIM(device) && !IS_FMODEL(device)) { if (FLD_TEST_DRF_NUM(_CTRL, _CPU_INTR_UNITS, _SEC0_INTR0_0, 1, val)) { status = _nvswitch_service_soe_fatal_ls10(device); if (status != NVL_SUCCESS) { NVSWITCH_PRINT(device, ERROR, "%s: Problem servicing SOE", __FUNCTION__); return_status = status; } } } } // step 4 -- retrigger engine interrupts _nvswitch_retrigger_engine_intr_ls10(device); // step 5 -- retrigger top level GIN interrupts NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_TOP_EN_CLEAR(0), 0xFFFFFFFF); NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_TOP_EN_SET(0), 0xFFFFFFFF); return return_status; } /* * Initialize interrupt tree HW for all units. * * Init and servicing both depend on bits matching across STATUS/MASK * and IErr STATUS/LOG/REPORT/CONTAIN registers. */ void nvswitch_initialize_interrupt_tree_ls10 ( nvswitch_device *device ) { NvU64 link_mask = nvswitch_get_enabled_link_mask(device); NvU32 i, val; // NPG/NPORT _nvswitch_initialize_nport_interrupts_ls10(device); // NXBAR _nvswitch_initialize_nxbar_interrupts_ls10(device); FOR_EACH_INDEX_IN_MASK(64, i, link_mask) { val = NVSWITCH_LINK_RD32(device, i, NVLW, _NVLW, _LINK_INTR_0_MASK(i)); val = FLD_SET_DRF(_NVLW, _LINK_INTR_0_MASK, _FATAL, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_0_MASK, _NONFATAL, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_0_MASK, _CORRECTABLE, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_0_MASK, _INTR0, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_0_MASK, _INTR1, _ENABLE, val); NVSWITCH_LINK_WR32(device, i, NVLW, _NVLW, _LINK_INTR_0_MASK(i), val); } FOR_EACH_INDEX_IN_MASK_END; FOR_EACH_INDEX_IN_MASK(64, i, link_mask) { val = NVSWITCH_LINK_RD32(device, i, NVLW, _NVLW, _LINK_INTR_1_MASK(i)); val = FLD_SET_DRF(_NVLW, _LINK_INTR_1_MASK, _FATAL, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_1_MASK, _NONFATAL, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_1_MASK, _CORRECTABLE, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_1_MASK, _INTR0, _ENABLE, val); val = FLD_SET_DRF(_NVLW, _LINK_INTR_1_MASK, _INTR1, _ENABLE, val); NVSWITCH_LINK_WR32(device, i, NVLW, _NVLW, _LINK_INTR_1_MASK(i), val); } FOR_EACH_INDEX_IN_MASK_END; // NVLIPT _nvswitch_initialize_nvlipt_interrupts_ls10(device); } // // Service Nvswitch NVLDL Fatal interrupts // NvlStatus nvswitch_service_nvldl_fatal_link_ls10 ( nvswitch_device *device, NvU32 nvlipt_instance, NvU32 link ) { ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); NvU32 pending, bit, unhandled; NvU32 dlDeferredIntrLinkMask = 0; NvBool bRequireResetAndDrain = NV_FALSE; NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; INFOROM_NVLINK_ERROR_EVENT error_event; report.raw_pending = NVSWITCH_LINK_RD32(device, link, NVLDL, _NVLDL_TOP, _INTR); report.raw_enable = NVSWITCH_LINK_RD32(device, link, NVLDL, _NVLDL_TOP, _INTR_STALL_EN); report.mask = report.raw_enable; pending = report.raw_pending & report.mask; error_event.nvliptInstance = (NvU8) nvlipt_instance; error_event.localLinkIdx = (NvU8) NVSWITCH_NVLIPT_GET_LOCAL_LINK_ID_LS10(link); if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_FAULT_RAM, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_TX_FAULT_RAM, "TX Fault Ram", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_TX_FAULT_RAM_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_FAULT_INTERFACE, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_TX_FAULT_INTERFACE, "TX Fault Interface", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_TX_FAULT_INTERFACE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_FAULT_SUBLINK_CHANGE, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_TX_FAULT_SUBLINK_CHANGE, "TX Fault Sublink Change", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_TX_FAULT_SUBLINK_CHANGE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_FAULT_SUBLINK_CHANGE, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_RX_FAULT_SUBLINK_CHANGE, "RX Fault Sublink Change", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_RX_FAULT_SUBLINK_CHANGE_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_FAULT_DL_PROTOCOL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_RX_FAULT_DL_PROTOCOL, "RX Fault DL Protocol", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_RX_FAULT_DL_PROTOCOL_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_PROTOCOL, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_LTSSM_PROTOCOL, "LTSSM Protocol Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); // TODO 2827793 this should be logged to the InfoROM as fatal } bit = DRF_NUM(_NVLDL_TOP, _INTR, _PHY_A, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_PHY_A, "PHY_A Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_PHY_A_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _TX_PL_ERROR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_TX_PL_ERROR, "TX_PL Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_TX_PL_ERROR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _RX_PL_ERROR, 1); if (nvswitch_test_flags(pending, bit)) { NVSWITCH_REPORT_FATAL(_HW_DLPL_RX_PL_ERROR, "RX_PL Error", NV_FALSE); nvswitch_clear_flags(&unhandled, bit); error_event.error = INFOROM_NVLINK_DL_RX_PL_ERROR_FATAL; nvswitch_inforom_nvlink_log_error_event(device, &error_event); } // // Note: LTSSM_FAULT_{UP/DOWN} must be the last interrupt serviced in the NVLDL // Fatal tree. The last step of handling this interrupt is going into the // reset_and_drain flow for the given link which will shutdown and reset // the link. The reset portion will also wipe away any link state including // pending DL interrupts. In order to log all error before wiping that state, // service all other interrupts before this one // bit = DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_DOWN, 1); if (nvswitch_test_flags(pending, bit)) { { dlDeferredIntrLinkMask |= bit; // // Since reset and drain will reset the link, including clearing // pending interrupts, skip the clear write below. There are cases // where link clocks will not be on after reset and drain so there // maybe PRI errors on writing to the register // bRequireResetAndDrain = NV_TRUE; } nvswitch_clear_flags(&unhandled, bit); } bit = DRF_NUM(_NVLDL_TOP, _INTR, _LTSSM_FAULT_UP, 1); if (nvswitch_test_flags(pending, bit)) { { dlDeferredIntrLinkMask |= bit; // // Since reset and drain will reset the link, including clearing // pending interrupts, skip the clear write below. There are cases // where link clocks will not be on after reset and drain so there // maybe PRI errors on writing to the register // bRequireResetAndDrain = NV_TRUE; } nvswitch_clear_flags(&unhandled, bit); } if (bRequireResetAndDrain) { // // If there is a link state callback enabled for this link then // we hit a consecutive FAULT_UP error. set bResetAndDrainRetry // so the current callback on completion can create a new // callback to retry the link state check to account for the added // delay caused by taking a 2nd fault and having to re-train // // If there is no callback enabled then set the error mask // and create the link errors deferred task. // if (chip_device->deferredLinkErrors[link].bLinkStateCallBackEnabled) { chip_device->deferredLinkErrors[link].bResetAndDrainRetry = NV_TRUE; } else { chip_device->deferredLinkErrors[link].fatalIntrMask.dl = dlDeferredIntrLinkMask; _nvswitch_create_deferred_link_errors_task_ls10(device, nvlipt_instance, link); } device->hal.nvswitch_reset_and_drain_links(device, NVBIT64(link)); } NVSWITCH_UNHANDLED_CHECK(device, unhandled); // Disable interrupts that have occurred after fatal error. if (device->link[link].fatal_error_occurred) { NVSWITCH_LINK_WR32(device, link, NVLDL, _NVLDL_TOP, _INTR_STALL_EN, report.raw_enable ^ pending); } if (!bRequireResetAndDrain) { NVSWITCH_LINK_WR32(device, link, NVLDL, _NVLDL_TOP, _INTR, pending); } if (unhandled != 0) { NVSWITCH_PRINT(device, WARN, "%s: Unhandled NVLDL fatal interrupts, link: %d pending: 0x%x enabled: 0x%x.\n", __FUNCTION__, link, pending, report.raw_enable); return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; } NvlStatus nvswitch_service_minion_link_ls10 ( nvswitch_device *device, NvU32 instance ) { NVSWITCH_INTERRUPT_LOG_TYPE report = { 0 }; NvU32 pending, unhandled, minionIntr, linkIntr, reg, enabledLinks, bit; NvU32 localLinkIdx, link; MINION_LINK_INTR minionLinkIntr = { 0 }; ls10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LS10(device); // // _MINION_MINION_INTR shows all interrupts currently at the host on this minion // Note: _MINIO_MINION_INTR is not used to clear link specific interrupts // minionIntr = NVSWITCH_MINION_RD32_LS10(device, instance, _MINION, _MINION_INTR); // get all possible interrupting links associated with this minion report.raw_pending = DRF_VAL(_MINION, _MINION_INTR, _LINK, minionIntr); // read in the enaled minion interrupts on this minion reg = NVSWITCH_MINION_RD32_LS10(device, instance, _MINION, _MINION_INTR_STALL_EN); // get the links with enabled interrupts on this minion enabledLinks = DRF_VAL(_MINION, _MINION_INTR_STALL_EN, _LINK, reg); report.raw_enable = enabledLinks; report.mask = report.raw_enable; // pending bit field contains interrupting links after being filtered pending = report.raw_pending & report.mask; if (pending == 0) { return -NVL_NOT_FOUND; } unhandled = pending; minionLinkIntr.bPending = NV_TRUE; FOR_EACH_INDEX_IN_MASK(32, localLinkIdx, pending) { link = (instance * NVSWITCH_LINKS_PER_NVLIPT_LS10) + localLinkIdx; bit = NVBIT(localLinkIdx); // read in the interrupt register for the given link linkIntr = NVSWITCH_MINION_LINK_RD32_LS10(device, link, _MINION, _NVLINK_LINK_INTR(localLinkIdx)); minionLinkIntr.regData = linkIntr; // _STATE must be set for _CODE to be valid if (!DRF_VAL(_MINION, _NVLINK_LINK_INTR, _STATE, linkIntr)) { continue; } NVSWITCH_PRINT(device, INFO, "%s: link[%d] {%d, %d} linkIntr = 0x%x\n", __FUNCTION__, link, instance, localLinkIdx, linkIntr); // // _MINION_INTR_LINK is a read-only register field for the host // Host must write 1 to _NVLINK_LINK_INTR_STATE to clear the interrupt on the link // reg = DRF_NUM(_MINION, _NVLINK_LINK_INTR, _STATE, 1); NVSWITCH_MINION_WR32_LS10(device, instance, _MINION, _NVLINK_LINK_INTR(localLinkIdx), reg); report.data[0] = linkIntr; switch(DRF_VAL(_MINION, _NVLINK_LINK_INTR, _CODE, linkIntr)) { case NV_MINION_NVLINK_LINK_INTR_CODE_NA: case NV_MINION_NVLINK_LINK_INTR_CODE_DLCMDFAULT: case NV_MINION_NVLINK_LINK_INTR_CODE_LOCAL_CONFIG_ERR: case NV_MINION_NVLINK_LINK_INTR_CODE_NEGOTIATION_CONFIG_ERR: case NV_MINION_NVLINK_LINK_INTR_CODE_BADINIT: case NV_MINION_NVLINK_LINK_INTR_CODE_PMFAIL: case NV_MINION_NVLINK_LINK_INTR_CODE_NOINIT: chip_device->deferredLinkErrors[link].fatalIntrMask.minionLinkIntr = minionLinkIntr; _nvswitch_create_deferred_link_errors_task_ls10(device, instance, link); break; case NV_MINION_NVLINK_LINK_INTR_CODE_SWREQ: NVSWITCH_PRINT(device, INFO, "%s: Received MINION Link SW Generate interrupt on MINION %d : link %d.\n", __FUNCTION__, instance, link); break; case NV_MINION_NVLINK_LINK_INTR_CODE_DLREQ: case NV_MINION_NVLINK_LINK_INTR_CODE_PMDISABLED: case NV_MINION_NVLINK_LINK_INTR_CODE_TLREQ: chip_device->deferredLinkErrors[link].nonFatalIntrMask.minionLinkIntr = minionLinkIntr; _nvswitch_create_deferred_link_errors_task_ls10(device, instance, link); case NV_MINION_NVLINK_LINK_INTR_CODE_NOTIFY: NVSWITCH_PRINT(device, INFO, "%s: Received MINION NOTIFY interrupt on MINION %d : link %d.\n", __FUNCTION__, instance, link); break; case NV_MINION_NVLINK_LINK_INTR_CODE_INBAND_BUFFER_AVAILABLE: { NVSWITCH_PRINT(device, INFO, "Received INBAND_BUFFER_AVAILABLE interrupt on MINION %d,\n", instance); nvswitch_minion_receive_inband_data_ls10(device, link); break; } default: NVSWITCH_REPORT_FATAL(_HW_MINION_FATAL_LINK_INTR, "Minion Interrupt code unknown", NV_FALSE); } nvswitch_clear_flags(&unhandled, bit); } FOR_EACH_INDEX_IN_MASK_END; NVSWITCH_UNHANDLED_CHECK(device, unhandled); if (unhandled != 0) { return -NVL_MORE_PROCESSING_REQUIRED; } return NVL_SUCCESS; }