diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b.h b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b.h index 4cb608b81..8643a8ee0 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b.h +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b.h @@ -30,7 +30,7 @@ struct gk20a; void ga10b_ltc_intr_configure(struct gk20a *g); -void ga10b_ltc_intr_isr(struct gk20a *g, u32 ltc); +int ga10b_ltc_intr_isr(struct gk20a *g, u32 ltc); void ga10b_ltc_intr3_configure_extra(struct gk20a *g, u32 *reg); void ga10b_ltc_intr3_interrupts(struct gk20a *g, u32 ltc, u32 slice, u32 ltc_intr3); diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b_fusa.c b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b_fusa.c index da927c61d..4dd28cdf4 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b_fusa.c +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_ga10b_fusa.c @@ -1078,13 +1078,19 @@ void ga10b_ltc_intr_handle_lts_intr(struct gk20a *g, u32 ltc, u32 slice) reg_value); } -void ga10b_ltc_intr_isr(struct gk20a *g, u32 ltc) +int ga10b_ltc_intr_isr(struct gk20a *g, u32 ltc) { u32 slice; + if (ltc >= nvgpu_ltc_get_ltc_count(g)) { + return -ENODEV; + } + for (slice = 0U; slice < g->ltc->slices_per_ltc; slice++) { ga10b_ltc_intr_handle_lts_intr(g, ltc, slice); ga10b_ltc_intr_handle_lts_intr2(g, ltc, slice); ga10b_ltc_intr_handle_lts_intr3(g, ltc, slice); } + + return 0; } diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.c b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.c index 907f497af..110b5f540 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.c +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.c @@ -1,7 +1,7 @@ /* * GM20B L2 INTR * - * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022 NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -61,12 +61,18 @@ static void gm20b_ltc_intr_handle_lts_interrupts(struct gk20a *g, nvgpu_safe_mult_u32(lts_stride, slice))), ltc_intr); } -void gm20b_ltc_intr_isr(struct gk20a *g, u32 ltc) +int gm20b_ltc_intr_isr(struct gk20a *g, u32 ltc) { u32 slice; + if (ltc >= nvgpu_ltc_get_ltc_count(g)) { + return -ENODEV; + } + for (slice = 0U; slice < g->ltc->slices_per_ltc; slice = nvgpu_safe_add_u32(slice, 1U)) { gm20b_ltc_intr_handle_lts_interrupts(g, ltc, slice); } + + return 0; } diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.h b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.h index 50d6d2f55..78eaa39d5 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.h +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gm20b.h @@ -1,7 +1,7 @@ /* * GM20B L2 INTR * - * Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,6 +30,6 @@ struct gk20a; void gm20b_ltc_intr_configure(struct gk20a *g); -void gm20b_ltc_intr_isr(struct gk20a *g, u32 ltc); +int gm20b_ltc_intr_isr(struct gk20a *g, u32 ltc); #endif diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.c b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.c index 84dd79667..c47562aeb 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.c +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.c @@ -1,7 +1,7 @@ /* * GP10B L2 INTR * - * Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,14 +33,20 @@ #include "ltc_intr_gp10b.h" #include "ltc_intr_gm20b.h" -void gp10b_ltc_intr_isr(struct gk20a *g, u32 ltc) +int gp10b_ltc_intr_isr(struct gk20a *g, u32 ltc) { u32 slice; + if (ltc >= nvgpu_ltc_get_ltc_count(g)) { + return -ENODEV; + } + for (slice = 0U; slice < g->ltc->slices_per_ltc; slice = nvgpu_safe_add_u32(slice, 1U)) { gp10b_ltc_intr_handle_lts_interrupts(g, ltc, slice); } + + return 0; } void gp10b_ltc_intr_configure(struct gk20a *g) diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.h b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.h index 61f22b1c5..219242f86 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.h +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gp10b.h @@ -1,7 +1,7 @@ /* * GP10B L2 INTR * - * Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -32,7 +32,7 @@ struct gk20a; void gp10b_ltc_intr_handle_lts_interrupts(struct gk20a *g, u32 ltc, u32 slice); #ifdef CONFIG_NVGPU_FALCON_NON_FUSA void gp10b_ltc_intr_configure(struct gk20a *g); -void gp10b_ltc_intr_isr(struct gk20a *g, u32 ltc); +int gp10b_ltc_intr_isr(struct gk20a *g, u32 ltc); #endif #endif diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b.h b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b.h index b467a7b4d..3b0c3f4f8 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b.h +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b.h @@ -1,7 +1,7 @@ /* * GV11B L2 INTR * - * Copyright (c) 2016-2021, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,7 +30,7 @@ struct gk20a; void gv11b_ltc_intr_configure(struct gk20a *g); -void gv11b_ltc_intr_isr(struct gk20a *g, u32 ltc); +int gv11b_ltc_intr_isr(struct gk20a *g, u32 ltc); #ifdef CONFIG_NVGPU_NON_FUSA void gv11b_ltc_intr_en_illegal_compstat(struct gk20a *g, bool enable); #endif diff --git a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b_fusa.c b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b_fusa.c index 55b4d762a..ed5dc17e2 100644 --- a/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b_fusa.c +++ b/drivers/gpu/nvgpu/hal/ltc/intr/ltc_intr_gv11b_fusa.c @@ -341,11 +341,17 @@ static void gv11b_ltc_intr_handle_lts_interrupts(struct gk20a *g, gv11b_ltc_intr_handle_ecc_sec_ded_interrupts(g, ltc, slice); } -void gv11b_ltc_intr_isr(struct gk20a *g, u32 ltc) +int gv11b_ltc_intr_isr(struct gk20a *g, u32 ltc) { u32 slice; + if (ltc >= nvgpu_ltc_get_ltc_count(g)) { + return -ENODEV; + } + for (slice = 0U; slice < g->ltc->slices_per_ltc; slice++) { gv11b_ltc_intr_handle_lts_interrupts(g, ltc, slice); } + + return 0; } diff --git a/drivers/gpu/nvgpu/include/nvgpu/gops/ltc.h b/drivers/gpu/nvgpu/include/nvgpu/gops/ltc.h index 85c52e282..b629d08e7 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gops/ltc.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gops/ltc.h @@ -196,7 +196,7 @@ struct gops_ltc_intr { * @return 0 in case of success, < 0 in case of failure. * @retval -ENODEV if invalid LTC number specified. */ - void (*isr)(struct gk20a *g, u32 ltc); + int (*isr)(struct gk20a *g, u32 ltc); /** @cond DOXYGEN_SHOULD_SKIP_THIS */ void (*configure)(struct gk20a *g); diff --git a/userspace/units/ltc/nvgpu-ltc.c b/userspace/units/ltc/nvgpu-ltc.c index 687b3a3a6..931c69002 100644 --- a/userspace/units/ltc/nvgpu-ltc.c +++ b/userspace/units/ltc/nvgpu-ltc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -609,6 +609,80 @@ done: return err; } +int test_ltc_intr_bvec(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 ltc_stride = nvgpu_get_litter_value(g, GPU_LIT_LTC_STRIDE); + u32 invalid_ltc[] = { NUM_LTC, U32_MAX }; + u32 valid_ltc[] = { 0, NUM_LTC - 1 }; + int err = UNIT_SUCCESS; + u32 ecc_status; + u32 ltc_intr3; + u32 offset; + u32 i; + + /* Init counter space */ + nvgpu_init_list_node(&g->ecc.stats_list); + + g->ltc->ltc_count = NUM_LTC; + err = NVGPU_ECC_COUNTER_INIT_PER_LTS(dstg_be_ecc_parity_count); + if (err != 0) { + unit_err(m, "failed to init dstg_be_ecc_parity_count\n"); + err = UNIT_FAIL; + goto done; + } + + /* Verify that isr for valid ltc (lts 0) is handled correctly. */ + for (i = 0; i < ARRAY_SIZE(valid_ltc); i++) { + offset = nvgpu_safe_mult_u32(ltc_stride, valid_ltc[i]); + ltc_intr3 = nvgpu_safe_add_u32(ltc_ltc0_lts0_intr3_r(), offset); + ecc_status = nvgpu_safe_add_u32( + ltc_ltc0_lts0_l2_cache_ecc_status_r(), offset); + + nvgpu_posix_io_writel_reg_space(g, nvgpu_safe_add_u32( + ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_r(), + offset), + ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_total_m()); + + nvgpu_posix_io_writel_reg_space(g, ltc_intr3, + ltc_ltcs_ltss_intr3_ecc_uncorrected_m()); + + nvgpu_posix_io_writel_reg_space(g, ecc_status, + ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_dstg_m()); + + g->ecc.ltc.dstg_be_ecc_parity_count[valid_ltc[i]][0].counter = 0; + + err = g->ops.ltc.intr.isr(g, valid_ltc[i]); + if ((err != 0) || + (g->ecc.ltc.dstg_be_ecc_parity_count[valid_ltc[i]][0].counter != + ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_total_m())) { + unit_err(m, "failed to process valid corrected ltc intr %u\n", i); + err = UNIT_FAIL; + goto done; + } + } + + /* Verify that isr for invalid ltc fails. */ + for (i = 0; i < ARRAY_SIZE(invalid_ltc); i++) { + err = g->ops.ltc.intr.isr(g, invalid_ltc[i]); + if (err == 0) { + unit_err(m, "processed invalid corrected ltc intr %u\n", i); + err = UNIT_FAIL; + goto done; + } + } + + err = UNIT_SUCCESS; + +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]); + } + } + + return err; +} + int test_ltc_intr_configure(struct unit_module *m, struct gk20a *g, void *args) { @@ -765,6 +839,7 @@ struct unit_module_test nvgpu_ltc_tests[] = { UNIT_TEST(ltc_functionality_tests, test_ltc_functionality_tests, NULL, 0), UNIT_TEST(ltc_intr, test_ltc_intr, NULL, 0), + UNIT_TEST(ltc_intr_bvec, test_ltc_intr_bvec, 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), #ifdef CONFIG_NVGPU_NON_FUSA diff --git a/userspace/units/ltc/nvgpu-ltc.h b/userspace/units/ltc/nvgpu-ltc.h index 0c6683172..6bf617f01 100644 --- a/userspace/units/ltc/nvgpu-ltc.h +++ b/userspace/units/ltc/nvgpu-ltc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -229,6 +229,43 @@ int test_ltc_remove_support(struct unit_module *m, int test_ltc_intr(struct unit_module *m, struct gk20a *g, void *args); /** + * Test specification for: test_ltc_intr_bvec + * + * Description: Validate ltc interrupt handler (isr) for valid and invalid LTC values. + * + * Test Type: Boundary Value + * + * Targets: gops_ltc_intr.isr, gv11b_ltc_intr_isr + * + * Input: test_ltc_init_support must have completed successfully. + * + * Equivalence classes: + * Variable: ltc + * - Valid: {0, NUM_LTC - 1} + * - Invalid: {NUM_LTC, U32_MAX} + * + * Steps: + * - Allocate ECC stat counter objects used by handler + * (dstg_be_ecc_parity_count). + * - Verify that isr for valid ltc (lts 0) is handled correctly. + * - Set the corrected counter in the ecc_uncorrected_err_count_r + * register for valid LTCs for LTS0. + * - Set the ecc_uncorrected_m in ltc_intr3 for valid LTCs. + * - Clear the dstg_be_ecc_parity_count for the valid LTC and LTS0. + * - Call the LTC isr through LTC unit gops.ltc.isr. + * - Verify that LTC isr is passing. + * - Verify that the dstg_be_ecc_parity_count is updated by the LTC isr. + * - Verify that isr for invalid ltc (lts 0) fails. + * - Call the LTC isr through LTC unit gops.ltc.isr. + * - Verify that LTC isr is failed. + * + * Output: Returns PASS if interrupt handler updates the counters correctly + * for valid LTCs and fails for invalid LTCs. + * Returns FAIL otherwise. + */ +int test_ltc_intr_bvec(struct unit_module *m, struct gk20a *g, void *args); + +/* * Test specification for: test_ltc_intr_configure * * Description: Validate the ltc interrupt configure API. diff --git a/userspace/units/mc/nvgpu-mc.c b/userspace/units/mc/nvgpu-mc.c index 80934ecd3..bc282d0f3 100644 --- a/userspace/units/mc/nvgpu-mc.c +++ b/userspace/units/mc/nvgpu-mc.c @@ -213,9 +213,11 @@ static int mock_gr_stall_isr(struct gk20a *g) return u.gr_isr_return; } -static void mock_ltc_isr(struct gk20a *g, u32 ltc) +static int mock_ltc_isr(struct gk20a *g, u32 ltc) { u.ltc_isr = true; + + return 0; } static void mock_pmu_isr(struct gk20a *g)