/*
* Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include "ecc_linux.h"
#include "os_linux.h"
#include "module.h"
/* This look-up table initializes the list of hw units and their errors.
* It also specifies the error injection mechanism supported, for each error.
* In case of hw error injection support, this initialization will be overriden
* by the values provided from the hal layes of corresponding hw units.
*/
static struct nvgpu_err_hw_module gv11b_err_lut[] = {
{
.name = "sm",
.hw_unit = (u32)NVGPU_ERR_MODULE_SM,
.num_errs = 21U,
.base_ecc_service_id =
NVGUARD_SERVICE_IGPU_SM_SWERR_L1_TAG_ECC_CORRECTED,
.errs = (struct nvgpu_err_desc[]) {
GPU_NONCRITERR("l1_tag_ecc_corrected",
GPU_SM_L1_TAG_ECC_CORRECTED, 0, 0),
GPU_CRITERR("l1_tag_ecc_uncorrected",
GPU_SM_L1_TAG_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("cbu_ecc_corrected", 0, 0, 0),
GPU_CRITERR("cbu_ecc_uncorrected",
GPU_SM_CBU_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("lrf_ecc_corrected", 0, 0, 0),
GPU_CRITERR("lrf_ecc_uncorrected",
GPU_SM_LRF_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("l1_data_ecc_corrected", 0, 0, 0),
GPU_CRITERR("l1_data_ecc_uncorrected",
GPU_SM_L1_DATA_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("icache_l0_data_ecc_corrected", 0, 0, 0),
GPU_CRITERR("icache_l0_data_ecc_uncorrected",
GPU_SM_ICACHE_L0_DATA_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("icache_l1_data_ecc_corrected", 0, 0, 0),
GPU_CRITERR("icache_l1_data_ecc_uncorrected",
GPU_SM_ICACHE_L1_DATA_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("icache_l0_predecode_ecc_corrected", 0, 0, 0),
GPU_CRITERR("icache_l0_predecode_ecc_uncorrected",
GPU_SM_ICACHE_L0_PREDECODE_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("l1_tag_miss_fifo_ecc_corrected", 0, 0, 0),
GPU_CRITERR("l1_tag_miss_fifo_ecc_uncorrected",
GPU_SM_L1_TAG_MISS_FIFO_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("l1_tag_s2r_pixprf_ecc_corrected", 0, 0, 0),
GPU_CRITERR("l1_tag_s2r_pixprf_ecc_uncorrected",
GPU_SM_L1_TAG_S2R_PIXPRF_ECC_UNCORRECTED, 0, 0),
GPU_CRITERR("machine_check_error", 0, 0, 0),
GPU_NONCRITERR("icache_l1_predecode_ecc_corrected", 0, 0, 0),
GPU_CRITERR("icache_l1_predecode_ecc_uncorrected",
GPU_SM_ICACHE_L1_PREDECODE_ECC_UNCORRECTED, 0, 0),
},
},
{
.name = "fecs",
.hw_unit = (u32)NVGPU_ERR_MODULE_FECS,
.num_errs = 4U,
.base_ecc_service_id =
NVGUARD_SERVICE_IGPU_FECS_SWERR_FALCON_IMEM_ECC_CORRECTED,
.errs = (struct nvgpu_err_desc[]) {
GPU_NONCRITERR("falcon_imem_ecc_corrected",
GPU_FECS_FALCON_IMEM_ECC_CORRECTED, 0, 0),
GPU_CRITERR("falcon_imem_ecc_uncorrected",
GPU_FECS_FALCON_IMEM_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("falcon_dmem_ecc_corrected", 0, 0, 0),
GPU_CRITERR("falcon_dmem_ecc_uncorrected",
GPU_FECS_FALCON_DMEM_ECC_UNCORRECTED, 0, 0),
},
},
{
.name = "pmu",
.hw_unit = NVGPU_ERR_MODULE_PMU,
.num_errs = 4U,
.base_ecc_service_id =
NVGUARD_SERVICE_IGPU_PMU_SWERR_FALCON_IMEM_ECC_CORRECTED,
.errs = (struct nvgpu_err_desc[]) {
GPU_NONCRITERR("falcon_imem_ecc_corrected",
GPU_PMU_FALCON_IMEM_ECC_CORRECTED, 0, 0),
GPU_CRITERR("falcon_imem_ecc_uncorrected",
GPU_PMU_FALCON_IMEM_ECC_UNCORRECTED, 0, 0),
GPU_NONCRITERR("falcon_dmem_ecc_corrected", 0, 0, 0),
GPU_CRITERR("falcon_dmem_ecc_uncorrected",
GPU_PMU_FALCON_DMEM_ECC_UNCORRECTED, 0, 0),
},
},
};
static void nvgpu_init_err_msg_header(struct gpu_err_header *header)
{
header->version.major = (u16)1U;
header->version.minor = (u16)0U;
header->sub_err_type = 0U;
header->sub_unit_id = 0UL;
header->address = 0UL;
header->timestamp_ns = 0UL;
}
static void nvgpu_init_ecc_err_msg(struct gpu_ecc_error_info *err_info)
{
nvgpu_init_err_msg_header(&err_info->header);
err_info->err_cnt = 0UL;
}
static void nvgpu_report_ecc_error_linux(struct gk20a *g, u32 hw_unit, u32 inst,
u32 err_id, u64 err_addr, u64 err_count)
{
int err = 0;
u32 s_id = 0;
u8 err_status = 0;
u8 err_info_size = 0;
u64 timestamp = 0ULL;
int err_threshold_counter = 0;
struct gpu_ecc_error_info err_pkt;
struct nvgpu_err_desc *err_desc = NULL;
struct nvgpu_err_hw_module *hw_module = NULL;
nv_guard_request_t req;
memset(&req, 0, sizeof(req));
nvgpu_init_ecc_err_msg(&err_pkt);
if (hw_unit >= sizeof(gv11b_err_lut)/sizeof(gv11b_err_lut[0])) {
err = -EINVAL;
goto done;
}
hw_module = &gv11b_err_lut[hw_unit];
if (err_id >= hw_module->num_errs) {
nvgpu_err(g, "invalid err_id (%u) for hw module (%u)",
err_id, hw_module->hw_unit);
err = -EINVAL;
goto done;
}
err_desc = &hw_module->errs[err_id];
timestamp = (u64)nvgpu_current_time_ns();
err_pkt.header.timestamp_ns = timestamp;
err_pkt.header.sub_unit_id = inst;
err_pkt.header.address = err_addr;
err_pkt.err_cnt = err_count;
err_info_size = sizeof(err_pkt);
s_id = hw_module->base_ecc_service_id + err_id;
if (err_desc->is_critical) {
err_status = NVGU