From 59282bdee85d4bf2b897fdab3c9372c39e47bf59 Mon Sep 17 00:00:00 2001 From: Tejal Kudav Date: Wed, 20 Nov 2019 11:40:44 +0530 Subject: [PATCH] gpu: nvgpu: unit: common.top tests Add unit tests for all the HALs exposed by common.top unit. JIRA NVGPU-2204 Change-Id: Id4866e181ba495c6e7d827ae534b76070677aa0e Signed-off-by: Tejal Kudav Reviewed-on: https://git-master.nvidia.com/r/2243164 Reviewed-by: mobile promotions Tested-by: mobile promotions --- Makefile.umbrella.tmk | 1 + drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 13 + userspace/Makefile.sources | 1 + userspace/SWUTS.h | 1 + userspace/SWUTS.sources | 1 + userspace/required_tests.json | 75 +++ userspace/units/top/Makefile | 26 + userspace/units/top/Makefile.interface.tmk | 23 + userspace/units/top/Makefile.tmk | 24 + userspace/units/top/nvgpu-top.c | 619 +++++++++++++++++++++ userspace/units/top/nvgpu-top.h | 416 ++++++++++++++ 11 files changed, 1200 insertions(+) create mode 100644 userspace/units/top/Makefile create mode 100644 userspace/units/top/Makefile.interface.tmk create mode 100644 userspace/units/top/Makefile.tmk create mode 100644 userspace/units/top/nvgpu-top.c create mode 100644 userspace/units/top/nvgpu-top.h diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index ff72fa705..c17d5478c 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -80,6 +80,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/enabled NV_REPOSITORY_COMPONENTS += userspace/units/falcon NV_REPOSITORY_COMPONENTS += userspace/units/falcon/falcon_tests NV_REPOSITORY_COMPONENTS += userspace/units/pmu +NV_REPOSITORY_COMPONENTS += userspace/units/top NV_REPOSITORY_COMPONENTS += userspace/units/gr NV_REPOSITORY_COMPONENTS += userspace/units/gr/falcon NV_REPOSITORY_COMPONENTS += userspace/units/gr/config diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index 7ad760137..abfab2251 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -26,6 +26,14 @@ gm20b_fb_tlb_invalidate gm20b_mm_get_big_page_sizes gm20b_gr_falcon_get_fecs_ctx_state_store_major_rev_id gm20b_ramin_set_big_page_size +gm20b_device_info_parse_enum +gm20b_is_engine_gr +gm20b_top_get_max_gpc_count +gm20b_top_get_max_tpc_per_gpc_count +gm20b_top_get_max_fbps_count +gm20b_top_get_max_ltc_per_fbp +gm20b_top_get_max_lts_per_ltc +gm20b_top_get_num_ltcs gp10b_get_max_page_table_levels gp10b_mm_get_default_big_page_size gp10b_mm_get_iommu_bit @@ -33,6 +41,10 @@ gp10b_mm_get_mmu_levels gp10b_mm_init_bar2_vm gp10b_mm_remove_bar2_vm gp10b_ramin_init_pdb +gp10b_device_info_parse_data +gp10b_get_num_engine_type_entries +gp10b_get_device_info +gp10b_is_engine_ce gv11b_channel_count gv11b_fb_intr_enable gv11b_fb_fault_buf_configure_hw @@ -97,6 +109,7 @@ gv11b_blcg_xbar_get_gating_prod gv11b_blcg_hshub_gating_prod_size gv11b_blcg_hshub_get_gating_prod gv11b_netlist_is_firmware_defined +gv11b_top_get_num_lce nvgpu_acr_construct_execute nvgpu_acr_init nvgpu_acr_is_lsf_lazy_bootstrap diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index 862268821..7cad5f7a9 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -92,6 +92,7 @@ UNITS := \ $(UNIT_SRC)/falcon/falcon_tests \ $(UNIT_SRC)/fuse \ $(UNIT_SRC)/pmu \ + $(UNIT_SRC)/top \ $(UNIT_SRC)/gr \ $(UNIT_SRC)/gr/falcon \ $(UNIT_SRC)/gr/config \ diff --git a/userspace/SWUTS.h b/userspace/SWUTS.h index 35f9a7aa2..14a9b222b 100644 --- a/userspace/SWUTS.h +++ b/userspace/SWUTS.h @@ -67,6 +67,7 @@ * - @ref SWUTS-cg * - @ref SWUTS-init_test * - @ref SWUTS-channel_os + * - @ref SWUTS-top * - @ref SWUTS-gr * - @ref SWUTS-gr-intr * - @ref SWUTS-gr-config diff --git a/userspace/SWUTS.sources b/userspace/SWUTS.sources index 9f4a6b4f3..a648fd9be 100644 --- a/userspace/SWUTS.sources +++ b/userspace/SWUTS.sources @@ -40,6 +40,7 @@ INPUT += ../../../userspace/units/posix/thread/posix-thread.h INPUT += ../../../userspace/units/posix/timers/posix-timers.h INPUT += ../../../userspace/units/ptimer/nvgpu-ptimer.h INPUT += ../../../userspace/units/acr/nvgpu-acr.h +INPUT += ../../../userspace/units/top/nvgpu-top.h INPUT += ../../../userspace/units/gr/nvgpu-gr.h INPUT += ../../../userspace/units/gr/intr/nvgpu-gr-intr.h INPUT += ../../../userspace/units/gr/config/nvgpu-gr-config.h diff --git a/userspace/required_tests.json b/userspace/required_tests.json index 12a05b511..64b03ba91 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -1558,6 +1558,81 @@ "test_level": 0, "unit": "nvgpu-pmu" }, + { + "test": "top_setup", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_device_info_parse_enum", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_is_engine_gr", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_max_gpc_count", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_max_tpc_per_gpc_count", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_max_fbps_count", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_max_ltc_per_fbp", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_max_lts_per_ltc", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_num_ltcs", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_device_info_parse_data", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_num_engine_type_entries", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_device_info", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_is_engine_ce", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_get_num_lce", + "test_level": 0, + "unit": "top" + }, + { + "test": "top_free_reg_space", + "test_level": 0, + "unit": "top" + }, { "test": "gr_falcon_init", "test_level": 0, diff --git a/userspace/units/top/Makefile b/userspace/units/top/Makefile new file mode 100644 index 000000000..e152a9328 --- /dev/null +++ b/userspace/units/top/Makefile @@ -0,0 +1,26 @@ +# Copyright (c) 2019, 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"), +# 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. + +.SUFFIXES: + +OBJS = nvgpu-top.o +MODULE = top + +include ../Makefile.units diff --git a/userspace/units/top/Makefile.interface.tmk b/userspace/units/top/Makefile.interface.tmk new file mode 100644 index 000000000..01f9b3d73 --- /dev/null +++ b/userspace/units/top/Makefile.interface.tmk @@ -0,0 +1,23 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All Rights Reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=top + +include $(NV_COMPONENT_DIR)/../Makefile.units.common.interface.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/top/Makefile.tmk b/userspace/units/top/Makefile.tmk new file mode 100644 index 000000000..9be5d5798 --- /dev/null +++ b/userspace/units/top/Makefile.tmk @@ -0,0 +1,24 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All Rights Reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=top +NVGPU_UNIT_SRCS=nvgpu-top.c + +include $(NV_COMPONENT_DIR)/../Makefile.units.common.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/top/nvgpu-top.c b/userspace/units/top/nvgpu-top.c new file mode 100644 index 000000000..c320844e5 --- /dev/null +++ b/userspace/units/top/nvgpu-top.c @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2019, 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"), + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nvgpu-top.h" + +/* + * Write callback. + */ +static void writel_access_reg_fn(struct gk20a *g, + struct nvgpu_reg_access *access) +{ + nvgpu_posix_io_writel_reg_space(g, access->addr, access->value); +} + +/* + * Read callback. + */ +static void readl_access_reg_fn(struct gk20a *g, + struct nvgpu_reg_access *access) +{ + access->value = nvgpu_posix_io_readl_reg_space(g, access->addr); +} + +static struct nvgpu_posix_io_callbacks test_reg_callbacks = { + /* Write APIs all can use the same accessor. */ + .writel = writel_access_reg_fn, + .writel_check = writel_access_reg_fn, + .bar1_writel = writel_access_reg_fn, + .usermode_writel = writel_access_reg_fn, + + /* Likewise for the read APIs. */ + .__readl = readl_access_reg_fn, + .readl = readl_access_reg_fn, + .bar1_readl = readl_access_reg_fn, +}; + +/* NV_TOP register space */ +#define NV_TOP_START 0x00022400U +#define NV_TOP_SIZE 0x000003FFU + +int test_setup(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 i; + u32 entry_count = 0U; + + /* Init HAL */ + g->ops.top.device_info_parse_enum = gm20b_device_info_parse_enum; + g->ops.top.device_info_parse_data = gp10b_device_info_parse_data; + g->ops.top.get_num_engine_type_entries = + gp10b_get_num_engine_type_entries; + g->ops.top.get_device_info = gp10b_get_device_info; + g->ops.top.is_engine_gr = gm20b_is_engine_gr; + g->ops.top.is_engine_ce = gp10b_is_engine_ce; + g->ops.top.get_max_gpc_count = gm20b_top_get_max_gpc_count; + g->ops.top.get_max_tpc_per_gpc_count = + gm20b_top_get_max_tpc_per_gpc_count; + g->ops.top.get_max_fbps_count = gm20b_top_get_max_fbps_count; + g->ops.top.get_max_ltc_per_fbp = gm20b_top_get_max_ltc_per_fbp; + g->ops.top.get_max_lts_per_ltc = gm20b_top_get_max_lts_per_ltc; + g->ops.top.get_num_ltcs = gm20b_top_get_num_ltcs; + g->ops.top.get_num_lce = gv11b_top_get_num_lce; + + /* Init register space */ + nvgpu_posix_io_init_reg_space(g); + + /* Map register space NV_TOP */ + if (nvgpu_posix_io_add_reg_space(g, NV_TOP_START, NV_TOP_SIZE) != 0) { + unit_err(m, "%s: failed to register space: NV_TOP\n", + __func__); + return UNIT_FAIL; + } + + (void)nvgpu_posix_register_io(g, &test_reg_callbacks); + + /* Setup a device_info_table + * We populate two entries for copy engine. + */ + entry_count = top_device_info__size_1_v(); + for (i = 0; i < entry_count ; i++) { + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(i), 0); + } + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(1), 0x90228C3E); + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(2), 0x8C10407D); + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(3), 0x0000004F); + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(4), 0x94230E3E); + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(5), 0xC8104085); + nvgpu_posix_io_writel_reg_space(g, top_device_info_r(6), 0x0000004F); + + return UNIT_SUCCESS; +} + +int test_free_reg_space(struct unit_module *m, struct gk20a *g, void *args) +{ + /* Free register space */ + nvgpu_posix_io_delete_reg_space(g, NV_TOP_START); + + return UNIT_SUCCESS; +} + +int test_device_info_parse_enum(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + int val = 0; + u32 engine_id = 0U; + u32 runlist_id = 0U; + u32 intr_id = 0U; + u32 reset_id = 0U; + u32 table_entry; + + /* Initialize table entry such that: + * 1. entry_type = enum = 2U. + * 2. engine, reset, interrupt and runlist bits are all valid. + * 3. engine_enum (Bits 29:26) = 4U. + * 4. runlist_enum (Bits 24:21) = 1U. + * 5. intr_enum (Bits 19:15) = 5U. + * 6. reset_enum (Bits 13:9) = 6U. + */ + table_entry = 0x10228C3E; + + /* Call top.device_info_parse_enum to parse the above table entry */ + val = g->ops.top.device_info_parse_enum(g, table_entry, &engine_id, + &runlist_id, &intr_id, + &reset_id); + + if (val != 0) { + unit_err(m, "Call to top.device_info_parse_enum() failed.\n"); + ret = UNIT_FAIL; + } + + /* Verify if the parsed data is as expected */ + if (engine_id != 4U) { + unit_err(m, + "device_info_parse_enum failed to parse engine_id.\n"); + ret = UNIT_FAIL; + } + if (runlist_id != 1U) { + unit_err(m, + "device_info_parse_enum failed to parse runlist_id.\n"); + ret = UNIT_FAIL; + } + if (intr_id != 5U) { + unit_err(m, + "device_info_parse_enum failed to parse intr_id.\n"); + ret = UNIT_FAIL; + } + if (reset_id != 6U) { + unit_err(m, + "device_info_parse_enum failed to parse reset_id.\n"); + ret = UNIT_FAIL; + } + + /* To get additional branch coverage, Set: + * 1. entry_type = enum = 2 + * 2. Engine_bit = invalid = 0. + * 3. runlist_bit = invalid = 0. + * 4. intr_bit = invalid = 0. + * 5. reset_bit = invalid = 0. + */ + table_entry = 0x10228C02; + + /* Call top.device_info_parse_enum to parse the above table entry */ + val = g->ops.top.device_info_parse_enum(g, table_entry, &engine_id, + &runlist_id, &intr_id, + &reset_id); + + if (val != 0) { + unit_err(m, "Call to top.device_info_parse_enum() failed.\n"); + ret = UNIT_FAIL; + } + + /* Verify if the parsed data is as expected */ + if (engine_id != U32_MAX) { + unit_err(m, + "device_info_parse_enum failed to parse engine_id.\n"); + ret = UNIT_FAIL; + } + if (runlist_id != U32_MAX) { + unit_err(m, + "device_info_parse_enum failed to parse runlist_id.\n"); + ret = UNIT_FAIL; + } + if (intr_id != U32_MAX) { + unit_err(m, + "device_info_parse_enum failed to parse intr_id.\n"); + ret = UNIT_FAIL; + } + if (reset_id != U32_MAX) { + unit_err(m, + "device_info_parse_enum failed to parse reset_id.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_max_gpc_count(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set max_gpc_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_num_gpcs_r(), 0x4U); + val = g->ops.top.get_max_gpc_count(g); + if (val != 4) { + unit_err(m, "max GPCs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set max_gpc_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_num_gpcs_r(), 0xE28A321DU); + val = g->ops.top.get_max_gpc_count(g); + if (val != 0x1D) { + unit_err(m, "max GPCs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_is_engine_gr(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + bool val; + + /* Set engine_type = 0 = graphics_enum */ + val = g->ops.top.is_engine_gr(g, 0U); + if (!val) { + unit_err(m, "API to check if engine is GR is incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set engine_type = 1 != graphics_enum */ + val = g->ops.top.is_engine_gr(g, 1U); + if (val) { + unit_err(m, "API to check if engine is GR is incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_max_tpc_per_gpc_count(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set max_tpc_per_gpc_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_tpc_per_gpc_r(), 0x4U); + val = g->ops.top.get_max_tpc_per_gpc_count(g); + if (val != 4) { + unit_err(m, "TPC per GPC parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set max_tpc_per_gpc_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_tpc_per_gpc_r(), 0xE28A321DU); + val = g->ops.top.get_max_tpc_per_gpc_count(g); + if (val != 0x1D) { + unit_err(m, "TPC per GPC parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_max_fbps_count(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set max_fbps_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_num_fbps_r(), 0x4U); + val = g->ops.top.get_max_fbps_count(g); + if (val != 4) { + unit_err(m, "max FBPs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set max_fbps_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_num_fbps_r(), 0xE28A321DU); + val = g->ops.top.get_max_fbps_count(g); + if (val != 0x1D) { + unit_err(m, "max FBPs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_max_ltc_per_fbp(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set max_ltc_per_fbp_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_ltc_per_fbp_r(), 0x4U); + val = g->ops.top.get_max_ltc_per_fbp(g); + if (val != 4) { + unit_err(m, " LTC per FBP parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set max_ltc_per_fbp_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_ltc_per_fbp_r(), 0xE28A321DU); + val = g->ops.top.get_max_ltc_per_fbp(g); + if (val != 0x1D) { + unit_err(m, "LTC per FBP parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_max_lts_per_ltc(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set max_lts_per_ltc_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_slices_per_ltc_r(), 0x4U); + val = g->ops.top.get_max_lts_per_ltc(g); + if (val != 4) { + unit_err(m, " LTS per LTC parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set max_lts_per_ltc_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_slices_per_ltc_r(), 0xE28A321DU); + val = g->ops.top.get_max_lts_per_ltc(g); + if (val != 0x1D) { + unit_err(m, "LTS per LTC parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_num_ltcs(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set num_ltcs_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_num_ltcs_r(), 0x4U); + val = g->ops.top.get_num_ltcs(g); + if (val != 4) { + unit_err(m, "LTCs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set num_ltcs_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_num_ltcs_r(), 0xE28A321DU); + val = g->ops.top.get_num_ltcs(g); + if (val != 0x1D) { + unit_err(m, "LTCs count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_device_info_parse_data(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + int val = 0; + u32 inst_id = 0U; + u32 pri_base = 0U; + u32 fault_id = 0U; + u32 table_entry; + + /* Initialize table entry such that: + * 1. entry_type = data = 1. + * 2. fault_id bit is valid. + * 3. fault_id_enum (Bits 9:3) = 15. + * 4. pri_base (Bits 23:12) = 0x104. + * 5. inst_id (Bits 29:25) = 3. + * 6. data_type = enum2 (bit 30) = 0. + */ + table_entry = 0x8C10407D; + + /* Call top.device_info_parse_data to parse the above table entry */ + val = g->ops.top.device_info_parse_data(g, table_entry, &inst_id, + &pri_base, &fault_id); + + if (val != 0) { + unit_err(m, "Call to top.device_info_parse_data() failed.\n"); + ret = UNIT_FAIL; + } + + /* Verify if the parsed data is as expected */ + if (inst_id != 3U) { + unit_err(m, + "device_info_parse_data failed to parse inst_id.\n"); + ret = UNIT_FAIL; + } + if (pri_base != 0x104000U) { + unit_err(m, + "device_info_parse_data failed to parse pri_base.\n"); + ret = UNIT_FAIL; + } + if (fault_id != 15U) { + unit_err(m, + "device_info_parse_data failed to parse fault_id.\n"); + ret = UNIT_FAIL; + } + + /* To get additional branch coverage, Set: + * 1. fault_id_bit = invalid = 0. + */ + table_entry = 0x8C104079; + + /* Call top.device_info_parse_data to parse the above table entry */ + val = g->ops.top.device_info_parse_data(g, table_entry, &inst_id, + &pri_base, &fault_id); + + if (val != 0) { + unit_err(m, "Call to top.device_info_parse_data() failed.\n"); + ret = UNIT_FAIL; + } + + /* Verify if the parsed data is as expected */ + if (fault_id != U32_MAX) { + unit_err(m, + "device_info_parse_data failed to parse fault_id.\n"); + ret = UNIT_FAIL; + } + + /* To cover an error branch, set table entry such that: + * 1. data_type != enum2. + */ + table_entry = 0xCC10407D; + + /* Call top.device_info_parse_data to parse the above table entry */ + val = g->ops.top.device_info_parse_data(g, table_entry, &inst_id, + &pri_base, &fault_id); + + /* Verify if the retval is as expected */ + if (val != -EINVAL) { + unit_err(m, + "device_info_parse_data failed to parse data type.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_num_engine_type_entries(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_SUCCESS; + int val = 0; + u32 engine_type = 19U; + + /* The device_info table is setup during test_setup(). We directly call + * get_num_engine_type_entries HAL to parse number of copy engine + * related entries in the device_info table. + */ + val = g->ops.top.get_num_engine_type_entries(g, engine_type); + + if (val != 2) { + unit_err(m, "top.get_num_engine_type_entries() failed.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_device_info(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + int val = 0; + struct nvgpu_device_info dev_info_1; + struct nvgpu_device_info *dev_info_2 = NULL; + u32 engine_type = 19U; + u32 inst_id = 3U; + + /* The device_info table is setup during test_setup(). We directly call + * get_device_info HAL to parse copy engine related information from the + * device_info table. + */ + val = g->ops.top.get_device_info(g, &dev_info_1, engine_type, inst_id); + + if (val != 0) { + unit_err(m, "Call to top.get_device_info() failed.\n"); + ret = UNIT_FAIL; + } + + /* Call HAL again to cover the error paths due to incorrect entry */ + inst_id = 2U; + val = g->ops.top.get_device_info(g, &dev_info_1, engine_type, inst_id); + + /* Verify if the retval is as expected */ + if (val != -EINVAL) { + unit_err(m, + "get_device_info() failed to handle incorrect entry.\n"); + ret = UNIT_FAIL; + } + + /* Call top.get_device_info with NULL pointer to cover error path */ + val = g->ops.top.get_device_info(g, dev_info_2, engine_type, inst_id); + + /* Verify if the retval is as expected */ + if (val != -EINVAL) { + unit_err(m, + "get_device_info() failed to handle NULL pointer.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_is_engine_ce(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + bool val; + + /* Set engine_type = 19 = copy engine enum */ + val = g->ops.top.is_engine_ce(g, 19U); + if (!val) { + unit_err(m, "API to check if engine is CE is incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set engine_type = 0 != copy engine enum */ + val = g->ops.top.is_engine_ce(g, 1U); + if (val) { + unit_err(m, "API to check if engine is CE is incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +int test_get_num_lce(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + u32 val; + + /* Set num_lce_count (Bits 4:0) = 4 */ + nvgpu_posix_io_writel_reg_space(g, top_num_ces_r(), 0x4U); + val = g->ops.top.get_num_lce(g); + if (val != 4) { + unit_err(m, "CE count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + /* Set num_lce_count (Bits 4:0) = 0x1D */ + nvgpu_posix_io_writel_reg_space(g, top_num_ces_r(), 0xE28A321DU); + val = g->ops.top.get_num_lce(g); + if (val != 0x1D) { + unit_err(m, "CE count parsing incorrect.\n"); + ret = UNIT_FAIL; + } + + return ret; +} + +struct unit_module_test top_tests[] = { + UNIT_TEST(top_setup, test_setup, NULL, 0), + UNIT_TEST(top_device_info_parse_enum, + test_device_info_parse_enum, NULL, 0), + UNIT_TEST(top_is_engine_gr, test_is_engine_gr, NULL, 0), + UNIT_TEST(top_get_max_gpc_count, test_get_max_gpc_count, NULL, 0), + UNIT_TEST(top_get_max_tpc_per_gpc_count, + test_get_max_tpc_per_gpc_count, NULL, 0), + UNIT_TEST(top_get_max_fbps_count, test_get_max_fbps_count, NULL, 0), + UNIT_TEST(top_get_max_ltc_per_fbp, + test_get_max_ltc_per_fbp, NULL, 0), + UNIT_TEST(top_get_max_lts_per_ltc, + test_get_max_lts_per_ltc, NULL, 0), + UNIT_TEST(top_get_num_ltcs, test_get_num_ltcs, NULL, 0), + UNIT_TEST(top_device_info_parse_data, + test_device_info_parse_data, NULL, 0), + UNIT_TEST(top_get_num_engine_type_entries, + test_get_num_engine_type_entries, NULL, 0), + UNIT_TEST(top_get_device_info, test_get_device_info, NULL, 0), + UNIT_TEST(top_is_engine_ce, test_is_engine_ce, NULL, 0), + UNIT_TEST(top_get_num_lce, test_get_num_lce, NULL, 0), + UNIT_TEST(top_free_reg_space, test_free_reg_space, NULL, 0), +}; + +UNIT_MODULE(top, top_tests, UNIT_PRIO_NVGPU_TEST); diff --git a/userspace/units/top/nvgpu-top.h b/userspace/units/top/nvgpu-top.h new file mode 100644 index 000000000..628bda2a7 --- /dev/null +++ b/userspace/units/top/nvgpu-top.h @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2019, 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"), + * 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. + */ + +#ifndef UNIT_NVGPU_TOP_H +#define UNIT_NVGPU_TOP_H + +struct gk20a; +struct unit_module; + +/** @addtogroup SWUTS-top + * @{ + * + * Software Unit Test Specification for nvgpu.common.top + */ + +/** + * Test specification for: test_setup + * + * Description: Setup prerequisites for tests. + * + * Test Type: Other (setup) + * + * Input: None + * + * Steps: + * - Initialize common.top HAL function pointers. + * - Map the register space for NV_TOP. + * - Register read/write callback functions. + * - Setup a device_info_table. + * + * Output: + * - UNIT_FAIL if encounters an error creating reg space + * - UNIT_SUCCESS otherwise + */ +int test_setup(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_free_reg_space + * + * Description: Free resources from test_setup() + * + * Test Type: Other (setup) + * + * Input: test_setup() has been executed. + * + * Steps: + * - Free up NV_TOP register space. + * + * Output: + * - UNIT_SUCCESS + */ +int test_free_reg_space(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_device_info_parse_enum + * + * Description: Verify the top.device_info_parse_enum HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Case 1: table entry to be parsed does not hit any error case + * - Initialize table entry such that: + * 1. entry_type = enum = 2U. + * 2. engine, reset, interrupt and runlist bits are all valid. + * 3. engine_enum (Bits 29:26) = 4U. + * 4. runlist_enum (Bits 24:21) = 1U. + * 5. intr_enum (Bits 19:15) = 5U. + * 6. reset_enum (Bits 13:9) = 6U. + * - So, table_entry = 0x10228C3E. + * - Call device_info_parse_enum HAL to parse the above table entry. + * - Verify if the parsed data is as expected. + * + * - Case 2: Setup table entry such that we hit error path branches. + * - Initialize table entry such that: + * 1. entry_type = enum = 2U. + * 2. Engine_bit = invalid = 0. + * 3. runlist_bit = invalid = 0. + * 4. intr_bit = invalid = 0. + * 5. reset_bit = invalid = 0. + * - So, table_entry = 0x10228C02. + * - Call device_info_parse_enum HAL to parse the above table entry. + * - Verify if the parsed data is as expected. + * + * Output: + * - UNIT_FAIL if above HAL does not parse enum as expected. + * - UNIT_SUCCESS otherwise + */ +int test_device_info_parse_enum(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_max_gpc_count + * + * Description: Verify the top.get_max_gpc_count HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to max_gpc_count (Bits 4:0) in + * top_num_gpcs_r() register to 4. + * - Call get_max_gpc_count HAL. + * - Verify the max_gpc_count is set to 4. + * - Repeat above steps with max_gpc_count set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse max_gpc_count. + * - UNIT_SUCCESS otherwise + */ +int test_get_max_gpc_count(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_is_engine_gr + * + * Description: Verify the top.is_engine_gr HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Call HAL with input equal to graphics enum = 0. + * - Verify the HAL returns true. + * - Call HAL with input not equal to graphics enum. + * - Verify the HAL returns false. + * + * Output: + * - UNIT_FAIL if above HAL returns false when input = graphics_enum and when + * it returns true when input != graphics enum. + * - UNIT_SUCCESS otherwise + */ +int test_is_engine_gr(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_get_max_tpc_per_gpc_count + * + * Description: Verify the top.get_max_tpc_per_gpc_count HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to max_tpc_per_gpc_count (Bits 4:0) in + * top_tpc_per_gpc_r() register to 4. + * - Call get_max_tpc_per_gpc_count HAL. + * - Verify the max_tpc_per_gpc_count is set to 4. + * - Repeat above steps with max_tpc_per_gpc_count set to 0x1D so that we make + * sure all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse max_tpc_per_gpc_count. + * - UNIT_SUCCESS otherwise + */ +int test_get_max_tpc_per_gpc_count(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_max_fbps_count + * + * Description: Verify the top.get_max_fbps_count HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to max_fbps_count (Bits 4:0) in + * top_num_fbps_r() register to 4. + * - Call get_max_fbps_count HAL. + * - Verify the max_fbps_count is set to 4. + * - Repeat above steps with max_fbps_count set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse max_fbps_count. + * - UNIT_SUCCESS otherwise + */ +int test_get_max_fbps_count(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_max_ltc_per_fbp + * + * Description: Verify the top.get_max_ltc_per_fbp HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to max_ltc_per_fbp (Bits 4:0) in + * top_ltc_per_fbp_r() register to 4. + * - Call get_max_ltc_per_fbp HAL. + * - Verify the max_ltc_per_fbp is set to 4. + * - Repeat above steps with max_ltc_per_fbp set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse max_ltc_per_fbp. + * - UNIT_SUCCESS otherwise + */ +int test_get_max_ltc_per_fbp(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_max_lts_per_ltc + * + * Description: Verify the top.get_max_lts_per_ltc HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to max_lts_per_ltc (Bits 4:0) in + * top_slices_per_ltc_r() register to 4. + * - Call get_max_lts_per_ltc HAL. + * - Verify the max_lts_per_ltc is set to 4. + * - Repeat above steps with max_lts_per_ltc set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse max_lts_per_ltc. + * - UNIT_SUCCESS otherwise + */ +int test_get_max_lts_per_ltc(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_num_ltcs + * + * Description: Verify the top.get_num_ltcs HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to num_ltcs (Bits 4:0) in + * top_num_ltcs_r() register to 4. + * - Call get_num_ltcs HAL. + * - Verify the num_ltcs is set to 4. + * - Repeat above steps with num_ltcs set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse num_ltcs. + * - UNIT_SUCCESS otherwise + */ +int test_get_num_ltcs(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_device_info_parse_data + * + * Description: Verify the top.device_info_parse_data HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Case 1: table entry to be parsed does not hit any error case + * - Initialize table entry such that: + * 1. entry_type = data = 1. + * 2. fault_id bit is valid. + * 3. fault_id_enum (Bits 9:3) = 15. + * 4. pri_base (Bits 23:12) = 0x104. + * 5. inst_id (Bits 29:25) = 3. + * 6. data_type = enum2 (bit 30) = 0. + * - So, table_entry = 0x8C10407D. + * - Call device_info_parse_data HAL to parse the above table entry. + * - Verify if the parsed data is as expected. + * + * - Case 2: Setup table entry such that we hit error path branch. + * - Initialize table entry such that: + * 1. fault_id_bit = invalid = 0. + * - So, table_entry = 0x8C104079. + * - Call device_info_parse_data HAL to parse the above table entry. + * - Verify if the parsed data is as expected. + * + * - Case 3: Setup table_entry such that the HAL fails with -EINVAL + * - Initialize table entry such that: + * 1. data_type != enum2 + * - So, table_entry = 0xCC10407D. + * - Call device_info_parse_data HAL to parse the above table entry. + * - Verify if the retval is as expected (-EINVAL). + * + * Output: + * - UNIT_FAIL if above HAL does not parse data as expected. + * - UNIT_SUCCESS otherwise + */ +int test_device_info_parse_data(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_num_engine_type_entries + * + * Description: Verify top.get_num_engine_type_entries HAL. + * + * Test Type: Feature Based + * + * Input: test_setup() has been executed. + * + * Steps: + * - The device_info table is setup during test_setup(). + * - The device_info table is initialized to have 2 copy engine entries. + * - Call get_num_engine_type_entries HAL to parse number of copy engine + * related entries in the device_info table. + * - Verify that number_of_entries = 2. + * + * Output: + * - UNIT_FAIL if above HAL does not return number of CE entries as expected. + * - UNIT_SUCCESS otherwise + */ +int test_get_num_engine_type_entries(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_get_device_info + * + * Description: Verify top.get_device_info HAL. + * + * Test Type: Feature Based + * + * Input: test_setup() has been executed. + * + * Steps: + * - The device_info table is setup during test_setup(). + * - The device_info table is initialized to have one copy engine entry. + * - Call get_device_info HAL to parse copy engine related data. + * - Here, we just make sure the call returns success; we do not check the + * parsed values as we have separate tests for verifying enum and data + * parsing code. + * - Call get_device_info HAL to parse copy engine entry with faulty entry + * - Verify if get_device_info HAL returns error(-EINVAL). + * - Call top.get_device_info with NULL pointer to cover error path. + * - Verify if the retval is as expected(-EINVAL). + * + * Output: + * - UNIT_FAIL if call to get_device_info HAL fails. + * - UNIT_SUCCESS otherwise + */ +int test_get_device_info(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_is_engine_ce + * + * Description: Verify the top.is_engine_ce HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Call HAL with input equal to copy engine enum = 0. + * - Verify the HAL returns true. + * - Call HAL with input not equal to copy engine enum. + * - Verify the HAL returns false. + * + * Output: + * - UNIT_FAIL if above HAL returns false when input = copy_engine_enum and when + * it returns true when input != copy_engine_enum. + * - UNIT_SUCCESS otherwise + */ +int test_is_engine_ce(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_get_num_lce + * + * Description: Verify the top.get_num_lce HAL. + * + * Test Type: Feature Based + * + * Input: None + * + * Steps: + * - Initialize bits corresponding to num_lce (Bits 4:0) in + * top_num_ces_r() register to 4. + * - Call get_num_lce HAL. + * - Verify the num_lce is set to 4. + * - Repeat above steps with num_lce set to 0x1D so that we make sure + * all 5 bits are parsed. + * + * Output: + * - UNIT_FAIL if above HAL fails to parse num_lce. + * - UNIT_SUCCESS otherwise + */ +int test_get_num_lce(struct unit_module *m, struct gk20a *g, void *args); + +#endif /* UNIT_NVGPU_TOP_H */