diff --git a/drivers/gpu/nvgpu/hal/ltc/ltc_gv11b_fusa.c b/drivers/gpu/nvgpu/hal/ltc/ltc_gv11b_fusa.c index 698a90037..4b13a4f20 100644 --- a/drivers/gpu/nvgpu/hal/ltc/ltc_gv11b_fusa.c +++ b/drivers/gpu/nvgpu/hal/ltc/ltc_gv11b_fusa.c @@ -50,7 +50,7 @@ void gv11b_ltc_init_fs_state(struct gk20a *g) nvgpu_log_info(g, "%u ltcs out of %u", g->ltc->ltc_count, g->ltc->max_ltc_count); - reg = gk20a_readl(g, ltc_ltcs_ltss_cbc_param_r()); + reg = nvgpu_readl(g, ltc_ltcs_ltss_cbc_param_r()); g->ltc->slices_per_ltc = ltc_ltcs_ltss_cbc_param_slices_per_ltc_v(reg);; g->ltc->cacheline_size = line_size << ltc_ltcs_ltss_cbc_param_cache_line_size_v(reg); diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index 658045def..fb3bb72d5 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -225,6 +225,7 @@ nvgpu_gr_obj_ctx_is_golden_image_ready nvgpu_gr_ctx_get_tsgid nvgpu_hr_timestamp nvgpu_init_ltc_support +nvgpu_ltc_ecc_free nvgpu_ltc_get_cacheline_size nvgpu_ltc_get_ltc_count nvgpu_ltc_get_slices_per_ltc @@ -268,6 +269,8 @@ nvgpu_dma_alloc_map_sys nvgpu_dma_alloc_sys nvgpu_dma_free nvgpu_dma_unmap_free +nvgpu_ecc_counter_init_per_lts +nvgpu_ecc_init_support nvgpu_engine_get_fast_ce_runlist_id nvgpu_engine_get_gr_runlist_id nvgpu_engine_is_valid_runlist_id diff --git a/userspace/required_tests.json b/userspace/required_tests.json index 49c3c0f14..8bb0dc99c 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -1061,6 +1061,18 @@ "unit": "nvgpu-acr", "test_level": 0 }, + { + "test": "test_determine_L2_size_bytes", + "case": "ltc_determine_L2_size", + "unit": "nvgpu-ltc", + "test_level": 0 + }, + { + "test": "test_ltc_ecc_init_free", + "case": "ltc_ecc_init_free", + "unit": "nvgpu-ltc", + "test_level": 0 + }, { "test": "test_ltc_functionality_tests", "case": "ltc_functionality_tests", @@ -1073,6 +1085,24 @@ "unit": "nvgpu-ltc", "test_level": 0 }, + { + "test": "test_ltc_intr", + "case": "ltc_intr", + "unit": "nvgpu-ltc", + "test_level": 0 + }, + { + "test": "test_ltc_intr_configure", + "case": "ltc_intr_configure", + "unit": "nvgpu-ltc", + "test_level": 0 + }, + { + "test": "test_ltc_intr_en_illegal_compstat", + "case": "ltc_intr_en_illegal_compstat", + "unit": "nvgpu-ltc", + "test_level": 0 + }, { "test": "test_ltc_negative_tests", "case": "ltc_negative_tests", @@ -1085,6 +1115,12 @@ "unit": "nvgpu-ltc", "test_level": 0 }, + { + "test": "test_ltc_set_enabled", + "case": "ltc_set_enabled", + "unit": "nvgpu-ltc", + "test_level": 0 + }, { "test": "test_netlist_init_support", "case": "netlist_init_support", diff --git a/userspace/units/ltc/nvgpu-ltc.c b/userspace/units/ltc/nvgpu-ltc.c index 28fc44d88..26fa9dd94 100644 --- a/userspace/units/ltc/nvgpu-ltc.c +++ b/userspace/units/ltc/nvgpu-ltc.c @@ -28,11 +28,16 @@ #include #include +#include #include #include #include +#include #include #include +#include +#include +#include #include "nvgpu-ltc.h" @@ -72,18 +77,38 @@ static struct nvgpu_posix_io_callbacks netlist_test_reg_callbacks = { .bar1_readl = readl_access_reg_fn, }; +#define NUM_LTC 2 +#define NUM_SLICES 2 +static u32 mock_enum_ltc(struct gk20a *g) +{ + return NUM_LTC; +} + +static int mock_ecc_init_fail(struct gk20a *g) +{ + return -1; +} int test_ltc_init_support(struct unit_module *m, struct gk20a *g, void *args) { int err = 0; + void (*save_void_func)(struct gk20a *g); + int (*save_ecc_func)(struct gk20a *g); + struct nvgpu_ltc *save_ptr; + struct nvgpu_posix_fault_inj *kmem_fi = + nvgpu_kmem_get_fault_injection(); nvgpu_posix_io_init_reg_space(g); if (nvgpu_posix_io_add_reg_space(g, mc_boot_0_r(), 0xfff) != 0) { unit_err(m, "%s: failed to create register space\n", __func__); return UNIT_FAIL; } + if (nvgpu_posix_io_add_reg_space(g, ltc_pltcg_base_v(), 0x3ffff) != 0) { + unit_err(m, "%s: failed to create register space\n", __func__); + return UNIT_FAIL; + } (void)nvgpu_posix_register_io(g, &netlist_test_reg_callbacks); @@ -93,6 +118,12 @@ int test_ltc_init_support(struct unit_module *m, g->params.gpu_arch = NV_PMC_BOOT_0_ARCHITECTURE_GV110; g->params.gpu_impl = NV_PMC_BOOT_0_IMPLEMENTATION_B; + /* + * Initialize slices in register + */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltcs_ltss_cbc_param_r(), + NUM_SLICES << 28); + /* * HAL init required for getting * the falcon ops initialized. @@ -102,13 +133,195 @@ int test_ltc_init_support(struct unit_module *m, unit_return_fail(m, "nvgpu_init_hal failed\n"); } + /* + * Init dependent ECC unit + */ + err = nvgpu_ecc_init_support(g); + if (err != 0) { + unit_return_fail(m, "ecc init failed\n"); + } + + /* + * Override HALs + */ + g->ops.priv_ring.enum_ltc = mock_enum_ltc; + + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + + /* + * Call init again after init to get branch coverage. + */ + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + + /* + * Call init again with this HAL set to NULL for branch coverage. + */ + save_void_func = g->ops.ltc.init_fs_state; + g->ops.ltc.init_fs_state = NULL; + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + /* and restore the HAL */ + g->ops.ltc.init_fs_state = save_void_func; + + /* + * Call init with this HAL set to NULL for branch coverage. + */ + save_void_func = g->ops.ltc.intr.configure; + g->ops.ltc.intr.configure = NULL; + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + /* and restore the HAL */ + g->ops.ltc.intr.configure = save_void_func; + + /* + * Call init with ecc init HAL NULL for branch coverage. + */ + save_ecc_func = g->ops.ltc.ecc_init; + g->ops.ltc.ecc_init = NULL; + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + + /* + * Call init with a failure returned from ecc init. This frees the ltc + * state in gk20a, so we'll need to init again. + */ + g->ops.ltc.ecc_init = mock_ecc_init_fail; + err = nvgpu_init_ltc_support(g); + if (err == 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + /* and restore the HAL */ + g->ops.ltc.ecc_init = save_ecc_func; + + /* + * Call init with ecc flag set to initialzed for branch coverage. + */ + g->ecc.initialized = true; + err = nvgpu_init_ltc_support(g); + if (err != 0) { + unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); + } + g->ecc.initialized = false; + + /* + * Call init with kmem fault inj enabled for branch coverage. + */ + save_ptr = g->ltc; + g->ltc = NULL; + nvgpu_posix_enable_fault_injection(kmem_fi, true, 0); + err = nvgpu_init_ltc_support(g); + if (err == 0) { + unit_return_fail(m, + "nvgpu_init_ltc_support incorrectly succeeded\n"); + } + /* and restore everything */ + nvgpu_posix_enable_fault_injection(kmem_fi, false, 0); + g->ltc = save_ptr; + + /* + * Call init one final time to setup the state variable properly for + * future tests. + */ err = nvgpu_init_ltc_support(g); if (err != 0) { unit_return_fail(m, "nvgpu_init_ltc_support failed\n"); } return UNIT_SUCCESS; +} +int test_ltc_ecc_init_free(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + int err; + struct nvgpu_ecc_stat **save_sec_ptr = g->ecc.ltc.ecc_sec_count; + struct nvgpu_ecc_stat **save_ded_ptr = g->ecc.ltc.ecc_ded_count; + struct nvgpu_posix_fault_inj *kmem_fi = + nvgpu_kmem_get_fault_injection(); + + err = nvgpu_gr_alloc(g); + if (err != 0) { + unit_return_fail(m, "failed to init gr\n"); + } + + g->ecc.ltc.ecc_sec_count = NULL; + g->ecc.ltc.ecc_ded_count = NULL; + + /* + * Call with failure on first kzalloc + */ + nvgpu_posix_enable_fault_injection(kmem_fi, true, 0); + err = g->ops.ltc.ecc_init(g); + if (err == 0) { + unit_err(m, "nvgpu_ecc_counter_init_per_lts() failed to return error\n"); + ret = UNIT_FAIL; + goto done; + } + + /* + * Call with failure on third kzalloc for the 2nd array dimension and to + * validate unrolling. + */ + nvgpu_posix_enable_fault_injection(kmem_fi, true, 2); + err = g->ops.ltc.ecc_init(g); + if (err == 0) { + unit_err(m, "nvgpu_ecc_counter_init_per_lts() failed to return error\n"); + ret = UNIT_FAIL; + goto done; + } + + /* Re-Init dependent ECC unit */ + err = nvgpu_ecc_init_support(g); + if (err != 0) { + unit_return_fail(m, "ecc init failed\n"); + } + + /* + * Call with failure on 4th kzalloc for second stat and get more + * branch/line coverage. + */ + nvgpu_posix_enable_fault_injection(kmem_fi, true, 4); + err = g->ops.ltc.ecc_init(g); + if (err == 0) { + unit_err(m, "nvgpu_ecc_counter_init_per_lts() failed to return error\n"); + ret = UNIT_FAIL; + goto done; + } + + /* Re-Init dependent ECC unit */ + err = nvgpu_ecc_init_support(g); + if (err != 0) { + unit_return_fail(m, "ecc init failed\n"); + } + + nvgpu_posix_enable_fault_injection(kmem_fi, false, 0); + err = g->ops.ltc.ecc_init(g); + if (err != 0) { + unit_err(m, "nvgpu_ecc_counter_init_per_lts() failed to init\n"); + ret = UNIT_FAIL; + goto done; + } + nvgpu_ltc_ecc_free(g); + +done: + nvgpu_posix_enable_fault_injection(kmem_fi, false, 0); + g->ecc.ltc.ecc_sec_count = save_sec_ptr; + g->ecc.ltc.ecc_ded_count = save_ded_ptr; + nvgpu_gr_free(g); + + return ret; } int test_ltc_functionality_tests(struct unit_module *m, @@ -122,11 +335,11 @@ int test_ltc_functionality_tests(struct unit_module *m, nvgpu_ltc_sync_enabled(g); ltc_count = nvgpu_ltc_get_ltc_count(g); - if (ltc_count != 0) { + if (ltc_count != NUM_LTC) { unit_return_fail(m, "nvgpu_ltc_get_ltc_count failed\n"); } slice_per_ltc = nvgpu_ltc_get_slices_per_ltc(g); - if (slice_per_ltc != 0) { + if (slice_per_ltc != NUM_SLICES) { unit_return_fail(m, "nvgpu_ltc_get_slices_per_ltc failed\n"); } cacheline_size = nvgpu_ltc_get_cacheline_size(g); @@ -142,6 +355,8 @@ int test_ltc_negative_tests(struct unit_module *m, { int err = 0; + g->mm.ltc_enabled_current = g->mm.ltc_enabled_target; + nvgpu_ltc_sync_enabled(g); g->ops.ltc.set_enabled = NULL; nvgpu_ltc_sync_enabled(g); nvgpu_ltc_remove_support(g); @@ -162,10 +377,263 @@ int test_ltc_remove_support(struct unit_module *m, return UNIT_SUCCESS; } +static int mock_l2_flush(struct gk20a *g, bool inv) +{ + return 0; +} + +int test_ltc_intr(struct unit_module *m, struct gk20a *g, void *args) +{ + int err = UNIT_SUCCESS; + u32 i; + const u32 offset1 = nvgpu_get_litter_value(g, GPU_LIT_LTC_STRIDE) * + nvgpu_get_litter_value(g, GPU_LIT_LTS_STRIDE); + int (*save_func)(struct gk20a *g, bool inv); + + /* Init counter space */ + nvgpu_init_list_node(&g->ecc.stats_list); + err = NVGPU_ECC_COUNTER_INIT_PER_LTS(ecc_sec_count); + if (err != 0) { + unit_err(m, "failed to init ecc_sec_count\n"); + err = UNIT_FAIL; + goto done; + } + err = NVGPU_ECC_COUNTER_INIT_PER_LTS(ecc_ded_count); + if (err != 0) { + unit_err(m, "failed to init ecc_ded_count\n"); + err = UNIT_FAIL; + goto done; + } + + /* test with no intr pending */ + g->ops.ltc.intr.isr(g, 0); + + /* test with intr, but no corrected or uncorrected bits */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set corrected & uncorrected overflow bits */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_total_counter_overflow_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_total_counter_overflow_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set corrected & uncorrected overflow bits in second instance */ + nvgpu_posix_io_writel_reg_space(g, + ltc_ltc0_lts0_l2_cache_ecc_status_r() + offset1, + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_total_counter_overflow_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_total_counter_overflow_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r() + offset1, + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set corrected overflow bit independently for branch coverage */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_total_counter_overflow_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set uncorrected overflow bit independently for branch coverage */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_total_counter_overflow_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* + * Clear the corrected & uncorrected overflow bits. And for branch + * coverage, set the uncorrected & corrected err counts. + */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), 0x0); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_r(), + ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_total_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_r(), + ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_total_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set dstg bits with data RAM */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_dstg_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_dstg_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set dstg bits with byte enable (BE) RAM */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_dstg_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_dstg_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_dstg_ecc_address_r(), + ltc_ltc0_lts0_dstg_ecc_address_info_ram_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set tstg & rstg bits */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_l2_cache_ecc_status_r(), + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_tstg_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_tstg_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_rstg_m() | + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_rstg_m()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* set sec & ded error bits */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr_r(), + ltc_ltcs_ltss_intr_ecc_sec_error_pending_f() | + ltc_ltcs_ltss_intr_ecc_ded_error_pending_f()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + + /* For branch coverage, set sec & ded error bits and make l2 flush succeed */ + save_func = g->ops.mm.cache.l2_flush; + g->ops.mm.cache.l2_flush = mock_l2_flush; + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr_r(), + ltc_ltcs_ltss_intr_ecc_sec_error_pending_f() | + ltc_ltcs_ltss_intr_ecc_ded_error_pending_f()); + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_intr3_r(), + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + g->ops.ltc.intr.isr(g, 0); + g->ops.mm.cache.l2_flush = save_func; + +done: + for (i = 0; i < nvgpu_ltc_get_ltc_count(g); i++) { + if (g->ecc.ltc.ecc_sec_count != NULL) { + nvgpu_kfree(g, g->ecc.ltc.ecc_sec_count[i]); + } + + if (g->ecc.ltc.ecc_ded_count != NULL) { + nvgpu_kfree(g, g->ecc.ltc.ecc_ded_count[i]); + } + } + + return err; +} + +int test_ltc_intr_en_illegal_compstat(struct unit_module *m, + struct gk20a *g, void *args) +{ + u32 val; + + /* clear the reg to be sure */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltcs_ltss_intr_r(), 0); + + g->ops.ltc.intr.en_illegal_compstat(g, true); + val = nvgpu_posix_io_readl_reg_space(g, ltc_ltcs_ltss_intr_r()); + if ((val & ltc_ltcs_ltss_intr_en_illegal_compstat_m()) == 0) { + unit_return_fail(m, "failed to enable illegal compstat\n"); + } + + g->ops.ltc.intr.en_illegal_compstat(g, false); + val = nvgpu_posix_io_readl_reg_space(g, ltc_ltcs_ltss_intr_r()); + if ((val & ltc_ltcs_ltss_intr_en_illegal_compstat_m()) != 0) { + unit_return_fail(m, "failed to disable illegal compstat\n"); + } + + return UNIT_SUCCESS; +} + +int test_ltc_intr_configure(struct unit_module *m, + struct gk20a *g, void *args) +{ + u32 val; + void (*save_func)(struct gk20a *g, bool en); + + g->ops.ltc.intr.configure(g); + val = nvgpu_posix_io_readl_reg_space(g, ltc_ltcs_ltss_intr_r()); + if ((val & (ltc_ltcs_ltss_intr_en_ecc_sec_error_enabled_f() | + ltc_ltcs_ltss_intr_en_ecc_ded_error_enabled_f())) != + (ltc_ltcs_ltss_intr_en_ecc_sec_error_enabled_f() | + ltc_ltcs_ltss_intr_en_ecc_ded_error_enabled_f())) { + unit_return_fail(m, "failed to configure intr\n"); + } + + /* for branch coverage test case where this HAL isn't configured */ + save_func = g->ops.ltc.intr.en_illegal_compstat; + g->ops.ltc.intr.en_illegal_compstat = NULL; + g->ops.ltc.intr.configure(g); + val = nvgpu_posix_io_readl_reg_space(g, ltc_ltcs_ltss_intr_r()); + if ((val & (ltc_ltcs_ltss_intr_en_ecc_sec_error_enabled_f() | + ltc_ltcs_ltss_intr_en_ecc_ded_error_enabled_f())) != + (ltc_ltcs_ltss_intr_en_ecc_sec_error_enabled_f() | + ltc_ltcs_ltss_intr_en_ecc_ded_error_enabled_f())) { + unit_return_fail(m, "failed to configure intr\n"); + } + g->ops.ltc.intr.en_illegal_compstat = save_func; + + return UNIT_SUCCESS; +} + +int test_determine_L2_size_bytes(struct unit_module *m, + struct gk20a *g, void *args) +{ + const u32 slice_size = 2; + const u32 slice_per_l2 = 2; + const u64 expected_size = g->ltc->ltc_count * slice_size * 1024 * slice_per_l2; + u64 val; + + nvgpu_posix_io_writel_reg_space(g, ltc_ltc0_lts0_tstg_info_1_r(), + (slice_size << 0) | + (slice_per_l2 << 16)); + val = g->ops.ltc.determine_L2_size_bytes(g); + if (val != expected_size) { + unit_return_fail(m, "incorrect L2 size reported %lld, expected %lld\n", + val, expected_size); + } + + return UNIT_SUCCESS; +} + +int test_ltc_set_enabled(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 val; + + /* clear reg */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r(), + 0x0); + g->ops.ltc.set_enabled(g, true); + val = nvgpu_posix_io_readl_reg_space(g, + ltc_ltcs_ltss_tstg_set_mgmt_2_r()); + /* enabling is actually disabling bypass, so logic seems backwards */ + if ((val & ltc_ltcs_ltss_tstg_set_mgmt_2_l2_bypass_mode_enabled_f()) + != 0) { + unit_return_fail(m, "not enabled\n"); + } + + /* clear reg */ + nvgpu_posix_io_writel_reg_space(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r(), + 0x0); + g->ops.ltc.set_enabled(g, false); + val = nvgpu_posix_io_readl_reg_space(g, + ltc_ltcs_ltss_tstg_set_mgmt_2_r()); + /* enabling is actually disabling bypass, so logic seems backwards */ + if ((val & ltc_ltcs_ltss_tstg_set_mgmt_2_l2_bypass_mode_enabled_f()) + == 0) { + unit_return_fail(m, "not disabled\n"); + } + + return UNIT_SUCCESS; +} + struct unit_module_test nvgpu_ltc_tests[] = { UNIT_TEST(ltc_init_support, test_ltc_init_support, NULL, 0), + UNIT_TEST(ltc_ecc_init_free, test_ltc_ecc_init_free, NULL, 0), UNIT_TEST(ltc_functionality_tests, test_ltc_functionality_tests, NULL, 0), + UNIT_TEST(ltc_intr, test_ltc_intr, NULL, 0), + UNIT_TEST(ltc_intr_en_illegal_compstat, + test_ltc_intr_en_illegal_compstat, NULL, 0), + UNIT_TEST(ltc_intr_configure, test_ltc_intr_configure, NULL, 0), + UNIT_TEST(ltc_determine_L2_size, test_determine_L2_size_bytes, NULL, 0), + UNIT_TEST(ltc_set_enabled, test_ltc_set_enabled, NULL, 0), UNIT_TEST(ltc_negative_tests, test_ltc_negative_tests, NULL, 0), UNIT_TEST(ltc_remove_support, test_ltc_remove_support, NULL, 0), }; diff --git a/userspace/units/ltc/nvgpu-ltc.h b/userspace/units/ltc/nvgpu-ltc.h index f96342470..50a9d9345 100644 --- a/userspace/units/ltc/nvgpu-ltc.h +++ b/userspace/units/ltc/nvgpu-ltc.h @@ -33,10 +33,12 @@ /** * Test specification for: test_ltc_init_support * - * Description: The ltc unit get initilized + * Description: The ltc unit gets initialized * * Test Type: Feature based * + * Targets: nvgpu_init_ltc_support + * * Input: None * * Steps: @@ -45,7 +47,13 @@ * - Register read/write IO callbacks. * - Setup init parameters to setup gv11b arch. * - Initialize hal to setup the hal functions. - * - Call nvgpu_init_ltc_support to initilize ltc unit. + * - Call nvgpu_init_ltc_support to initialize ltc unit. + * - Call nvgpu_init_ltc_support a second time to get branch coverage for + * already initialzed ltc. Call should not fail. + * - Call nvgpu_init_ltc_support with the init_fs_state HAL set to zero. Call + * should not fail. + * - Call nvgpu_init_ltc_support with fault injection enabled for + * nvgpu_kzalloc. Call should fail, but not crash. * * Output: Returns PASS if the steps above were executed successfully. FAIL * otherwise. @@ -53,15 +61,56 @@ int test_ltc_init_support(struct unit_module *m, struct gk20a *g, void *args); +/** + * Test specification for: test_ltc_ecc_init_free + * + * Description: Validate ltc unit initialization of ecc counters. + * + * Test Type: Feature based + * + * Targets: nvgpu_ecc_counter_init_per_lts, gv11b_lts_ecc_init, + * nvgpu_ltc_ecc_free + * + * Input: test_ltc_init_support must have completed successfully. + * + * Steps: + * - Call nvgpu_gr_alloc() since parts of the gr structure are required for + * the failure paths. + * - Save the current ecc count pointers from the gk20a struct and set the gk20a + * pointers to NULL. + * - Setup kmem fault injection to trigger fault on allocation for first alloc. + * - Call ltc ecc counter init and verify error is returned. + * - Setup kmem fault injection to trigger fault on allocation for third alloc + * to validate failures to allocate on second dimension of array. + * - Call ltc ecc counter init and verify error is returned. + * - Re-init ecc support. + * - Setup kmem fault injection to trigger fault on allocation for fifth alloc + * to validate failures to allocate for second ltc ecc stat. + * - Call ltc ecc counter init and verify error is returned. + * - Re-init ecc support. + * - Disable kmem fault injection. + * - Call ltc ecc counter init and verify no error is returned. + * - Call ltc ecc counter free. + * - Restore gk20a ltc ecc counter pointers to previous values. + * - Free gr structures. + * + * Output: Returns PASS if the steps above were executed successfully. FAIL + * otherwise. + */ +int test_ltc_ecc_init_free(struct unit_module *m, struct gk20a *g, void *args); + /** * Test specification for: test_ltc_functionality_tests * * Description: This test test ltc sync enabled and queries data * related to different ltc data. - * Checks whether valid data is retured or not. + * Checks whether valid data is returned or not. * * Test Type: Feature based * + * Targets: nvgpu_ltc_sync_enabled, nvgpu_ltc_get_ltc_count, + * nvgpu_ltc_get_slices_per_ltc, nvgpu_ltc_get_cacheline_size + * * Input: None * * Steps: @@ -74,7 +123,6 @@ int test_ltc_init_support(struct unit_module *m, * * Output: Returns PASS if returned data is valid. FAIL otherwise. */ - int test_ltc_functionality_tests(struct unit_module *m, struct gk20a *g, void *args); @@ -85,6 +133,9 @@ int test_ltc_functionality_tests(struct unit_module *m, * * Test Type: Feature based * + * Targets: nvgpu_ltc_sync_enabled, nvgpu_ltc_remove_support, + * nvgpu_init_ltc_support + * * Input: None * * Steps: @@ -104,6 +155,8 @@ int test_ltc_negative_tests(struct unit_module *m, * * Test Type: Feature based * + * Targets: nvgpu_ltc_remove_support + * * Input: None * * Steps: @@ -114,4 +167,174 @@ int test_ltc_negative_tests(struct unit_module *m, int test_ltc_remove_support(struct unit_module *m, struct gk20a *g, void *args); +/** + * Test specification for: test_ltc_intr + * + * Description: Validate ltc interrupt handler (isr). The ltc isr is responsible + * for reporting errors determind from the ltc status registers. + * + * Test Type: Feature based + * + * Targets: gv11b_ltc_intr_isr + * + * Input: test_ltc_init_support must have completed successfully. + * + * Steps: + * - Allocate ECC stat counter objects used by handler (ecc_sec_count, + * ecc_ded_count). + * - Test LTC isr with no interrupts pending. + * - Test with corrected and uncorrected bits in the first LTC instances. + * - Set the corrected & uncorrected counter overflow bits in the first + * ecc_status register (NV_PLTCG_LTC0_LTS0_L2_CACHE_ECC_STATUS). + * - Set the interrupt pending bit in the first LTC interrupt register + * (NV_PLTCG_LTC0_LTS0_INTR). + * - Call the LTC isr. + * - Test with corrected and uncorrected bits in the second LTC instance. + * - Set the corrected & uncorrected counter overflow bits in the second + * ecc_status register. + * - Set the interrupt pending bit in the second LTC interrupt register. + * - Call the LTC isr. + * - Test with corrected bits only (for branch coverage). + * - Set the corrected counter overflow bit and not the uncorrected bit in + * the ecc_status register. + * - Set the interrupt pending bit in the LTC interrupt register. + * - Call the LTC isr. + * - Test with uncorrected bits only (for branch coverage). + * - Set the uncorrected counter overflow bit and not the corrected bit in + * the ecc_status register. + * - Set the interrupt pending bit in the LTC interrupt register. + * - Call the LTC isr. + * - Test with corrected and uncorrected error counts but without err bits (for + * branch coverage). + * - Clear the corrected & uncorrected counter overflow bits in the second + * ecc_status register. + * - Write values to the corrected & uncorrected count registers. + * - Set the interrupt pending bit in the second LTC interrupt register. + * - Call the LTC isr. + * - Test handling of dstg error in data RAM. + * - Set the dstg corrected & uncorrected error bits in the ecc_status + * register. + * - Set the dstg RAM mask field of the dstg_ecc_address register + * (NV_PLTCG_LTC0_LTS0_DSTG_ECC_ADDRESS) to report data RAM. + * - Set the interrupt pending bit in the first LTC interrupt register. + * - Call the LTC isr. + * - Test handling of dstg error in byte enable (BE) RAM. + * - Set the dstg corrected & uncorrected error bits in the ecc_status + * register. + * - Set the dstg RAM mask field of the dstg_ecc_address register to report + * BE RAM. + * - Set the interrupt pending bit in the first LTC interrupt register. + * - Call the LTC isr. + * - Test handling of tstg and rstg errors. + * - Set the tstg and rstg, corrected & uncorrected counter error bits in the + * ecc_status register. + * - Set the interrupt pending bit in the first LTC interrupt register. + * - Call the LTC isr. + * - Test handling of sec and ded errors. + * - Set the sec and ded pending error bits in the ecc_status register. + * - Set the interrupt pending bit in the first LTC interrupt register. + * - Call the LTC isr. + * - Test handling of sec and ded errors when the l2 flush API succeeds (for + * branch coverage). + * - Override the MM l2_flush HAL to return success. + * - Set the sec and ded pending error bits in the ecc_status register. + * - Set the interrupt pending bit in the first LTC interrupt register. + * - Call the LTC isr. + * + * Output: Returns PASS unless counter initialization fails or an except occurs + * in interrupt handler. + */ +int test_ltc_intr(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_ltc_intr_en_illegal_compstat + * + * Description: Validate the inter_en_illegal_compstat API. + * + * Test Type: Feature based + * + * Targets: gv11b_ltc_intr_en_illegal_compstat + * + * Input: None + * + * Steps: + * - Clear the LTC intr register (NV_PLTCG_LTCS_LTSS_INTR). + * - Call the gv11b_ltc_intr_en_illegal_compstat HAL requesting enable. + * - Verify correct setting in LTC intr register. + * - Call the gv11b_ltc_intr_en_illegal_compstat HAL requesting disable. + * - Verify correct setting in LTC intr register. + * + * Output: Returns PASS if register is configured correctly. FAIL otherwise. + */ +int test_ltc_intr_en_illegal_compstat(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_ltc_intr_configure + * + * Description: Validate the ltc interrupt configure API. + * + * Test Type: Feature based + * + * Targets: gv11b_ltc_intr_configure + * + * Input: None + * + * Steps: + * - Call the gv11b_ltc_intr_configure HAL. + * - Verify correct setting in LTC intr register (NV_PLTCG_LTCS_LTSS_INTR). + * - For branch coverage, verify handling when en_illegal_compstat HAL is NULL. + * - Set en_illegal_compstat HAL to NULL. + * - Call the gv11b_ltc_intr_configure HAL. + * - Verify correct setting in LTC intr register. + * + * Output: Returns PASS if register is configured correctly. FAIL otherwise. + */ +int test_ltc_intr_configure(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_determine_L2_size_bytes + * + * Description: Validate the ltc API to determine L2 size. + * + * Test Type: Feature based + * + * Targets: gp10b_determine_L2_size_bytes + * + * Input: test_ltc_init_support must have completed successfully. + * + * Steps: + * - Set the L2 configuration in the ltc NV_PLTCG_LTC0_LTSS_TSTG_INFO_ register. + * - Call the gp10b_determine_L2_size_bytes HAL. + * - Verify the correct L2 size is returned. + * + * Output: Returns PASS if correct size returned. FAIL otherwise. + */ +int test_determine_L2_size_bytes(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_ltc_set_enabled + * + * Description: Validate the ltc API to enable level 2 cache. + * + * Test Type: Feature based + * + * Targets: gp10b_ltc_set_enabled + * + * Input: None + * + * Steps: + * - Clear the NV_PLTCG_LTCS_LTSS_TSTG_SET_MGMT_2 register + * - Call the gp10b_ltc_set_enabled HAL requesting enable. + * - Verify the L2 bypass mode is disabled in NV_PLTCG_LTCS_LTSS_TSTG_SET_MGMT_2. + * - Clear the NV_PLTCG_LTCS_LTSS_TSTG_SET_MGMT_2 register + * - Call the gp10b_ltc_set_enabled HAL requesting disable. + * - Verify the L2 bypass mode is enabled in NV_PLTCG_LTCS_LTSS_TSTG_SET_MGMT_2. + * + * Output: Returns PASS if register is configured correctly. FAIL otherwise. + */ +int test_ltc_set_enabled(struct unit_module *m, struct gk20a *g, void *args); + #endif /* UNIT_NVGPU_LTC_H */