From 5f0d1f39c2a7f66d4e49055112309ae96c25dc63 Mon Sep 17 00:00:00 2001 From: Philip Elcan Date: Wed, 4 Dec 2019 17:03:28 -0500 Subject: [PATCH] gpu: nvgpu: unit: create mc unit test JIRA NVGPU-2224 Change-Id: Ic433e8bc2ac583c1735203d1b5f0fd61942c33d4 Signed-off-by: Philip Elcan Reviewed-on: https://git-master.nvidia.com/r/2257128 GVS: Gerrit_Virtual_Submit Reviewed-by: Alex Waterman Reviewed-by: mobile promotions Tested-by: mobile promotions --- Makefile.umbrella.tmk | 1 + drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 8 + userspace/Makefile.sources | 1 + userspace/required_tests.json | 72 ++ userspace/units/mc/Makefile | 26 + userspace/units/mc/Makefile.interface.tmk | 23 + userspace/units/mc/Makefile.tmk | 24 + userspace/units/mc/nvgpu-mc.c | 805 +++++++++++++++++++++ userspace/units/mc/nvgpu-mc.h | 358 +++++++++ 9 files changed, 1318 insertions(+) create mode 100644 userspace/units/mc/Makefile create mode 100644 userspace/units/mc/Makefile.interface.tmk create mode 100644 userspace/units/mc/Makefile.tmk create mode 100644 userspace/units/mc/nvgpu-mc.c create mode 100644 userspace/units/mc/nvgpu-mc.h diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index 7cce059ee..bf611e456 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -54,6 +54,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/interface/rbtree NV_REPOSITORY_COMPONENTS += userspace/units/pramin NV_REPOSITORY_COMPONENTS += userspace/units/priv_ring NV_REPOSITORY_COMPONENTS += userspace/units/ptimer +NV_REPOSITORY_COMPONENTS += userspace/units/mc NV_REPOSITORY_COMPONENTS += userspace/units/mm/nvgpu_sgt NV_REPOSITORY_COMPONENTS += userspace/units/mm/nvgpu_mem NV_REPOSITORY_COMPONENTS += userspace/units/mm/allocators/buddy_allocator diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index e719e4463..fb895c9e3 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -436,6 +436,13 @@ nvgpu_kmem_get_fault_injection nvgpu_kzalloc_impl nvgpu_vmalloc_impl nvgpu_log_msg_impl +nvgpu_mc_intr_mask +nvgpu_mc_intr_nonstall_pause +nvgpu_mc_intr_nonstall_resume +nvgpu_mc_intr_nonstall_unit_config +nvgpu_mc_intr_stall_pause +nvgpu_mc_intr_stall_resume +nvgpu_mc_intr_stall_unit_config nvgpu_memset nvgpu_mem_create_from_phys nvgpu_mem_iommu_translate @@ -613,6 +620,7 @@ nvgpu_vm_put nvgpu_vm_put_buffers nvgpu_vm_unmap nvgpu_vzalloc_impl +nvgpu_wait_for_deferred_interrupts nvgpu_writel nvgpu_writel_check nvgpu_clear_bit diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index 12a025c66..f8aff3fc0 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -62,6 +62,7 @@ UNITS := \ $(UNIT_SRC)/interface/lock \ $(UNIT_SRC)/interface/atomic \ $(UNIT_SRC)/interface/rbtree \ + $(UNIT_SRC)/mc \ $(UNIT_SRC)/mm/nvgpu_sgt \ $(UNIT_SRC)/mm/allocators/buddy_allocator \ $(UNIT_SRC)/mm/allocators/nvgpu_allocator \ diff --git a/userspace/required_tests.json b/userspace/required_tests.json index ed2048c1a..7af995ddb 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -1055,6 +1055,78 @@ "unit": "list", "test_level": 0 }, + { + "test": "test_enable_disable_reset", + "case": "enable_disable_reset", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_is_stall_and_eng_intr_pending", + "case": "intr_is_stall_and_eng_intr_pending", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_intr_stall", + "case": "intr_stall", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_is_intr1_pending", + "case": "is_intr1_pending", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_isr_nonstall", + "case": "isr_nonstall", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_isr_stall", + "case": "isr_stall", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_free_env", + "case": "mc_free_env", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_setup_env", + "case": "mc_setup_env", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_pause_resume_mask", + "case": "pause_resume_mask", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_reset_mask", + "case": "reset_mask", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_unit_config", + "case": "unit_config", + "unit": "mc", + "test_level": 0 + }, + { + "test": "test_wait_for_deferred_interrupts", + "case": "wait_for_deferred_interrupts", + "unit": "mc", + "test_level": 0 + }, { "test": "test_as_alloc_share", "case": "as_alloc_share_0k_um", diff --git a/userspace/units/mc/Makefile b/userspace/units/mc/Makefile new file mode 100644 index 000000000..0c29750ce --- /dev/null +++ b/userspace/units/mc/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-mc.o +MODULE = mc + +include ../Makefile.units diff --git a/userspace/units/mc/Makefile.interface.tmk b/userspace/units/mc/Makefile.interface.tmk new file mode 100644 index 000000000..2c9dd0b86 --- /dev/null +++ b/userspace/units/mc/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=mc + +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/mc/Makefile.tmk b/userspace/units/mc/Makefile.tmk new file mode 100644 index 000000000..1bd5ffdf6 --- /dev/null +++ b/userspace/units/mc/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=mc +NVGPU_UNIT_SRCS=nvgpu-mc.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/mc/nvgpu-mc.c b/userspace/units/mc/nvgpu-mc.c new file mode 100644 index 000000000..405dac1bf --- /dev/null +++ b/userspace/units/mc/nvgpu-mc.c @@ -0,0 +1,805 @@ +/* + * 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 + +#include +#include + +#include "nvgpu-mc.h" + +#define MC_ADDR_SPACE_START 0x00000000 +#define MC_ADDR_SPACE_SIZE 0xfff + +/* value for GV11B */ +#define MC_BOOT_0_GV11B (NVGPU_GPUID_GV11B << 20) +/* to set the security fuses */ +#define GP10B_FUSE_REG_BASE 0x00021000U +#define GP10B_FUSE_OPT_PRIV_SEC_EN (GP10B_FUSE_REG_BASE+0x434U) +#define ACTIVE_GR_ID 1 +#define ACTIVE_CE_ID 2 + +#define STALL_EN_REG mc_intr_en_set_r(NVGPU_MC_INTR_STALLING) +#define STALL_DIS_REG mc_intr_en_clear_r(NVGPU_MC_INTR_STALLING) +#define NONSTALL_EN_REG mc_intr_en_set_r(NVGPU_MC_INTR_NONSTALLING) +#define NONSTALL_DIS_REG mc_intr_en_clear_r(NVGPU_MC_INTR_NONSTALLING) +#define STALL_PENDING_REG mc_intr_r(NVGPU_MC_INTR_STALLING) +#define NONSTALL_PENDING_REG mc_intr_r(NVGPU_MC_INTR_NONSTALLING) + +struct mc_unit { + u32 num; + u32 bit; +}; +static struct mc_unit mc_units[] = { + { MC_INTR_UNIT_BUS, mc_intr_pbus_pending_f() }, + { MC_INTR_UNIT_PRIV_RING, mc_intr_priv_ring_pending_f() }, + { MC_INTR_UNIT_FIFO, mc_intr_pfifo_pending_f() }, + { MC_INTR_UNIT_LTC, mc_intr_ltc_pending_f() }, + { MC_INTR_UNIT_HUB, mc_intr_replayable_fault_pending_f() }, + { MC_INTR_UNIT_GR, (1 << ACTIVE_GR_ID) /* nvgpu_gr_engine_interrupt_mask() */}, + { MC_INTR_UNIT_PMU, mc_intr_pmu_pending_f() }, + { MC_INTR_UNIT_CE, (1 << ACTIVE_CE_ID) /* nvgpu_ce_engine_interrupt_mask() */ }, +}; +#define NUM_MC_UNITS ARRAY_SIZE(mc_units) + +#define INVALID_UNIT 100 +/* + * Mock I/O + */ + +/* + * Write callback. Forward the write access to the mock IO framework. + */ +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. Get the register value from the mock IO framework. + */ +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, +}; + +struct unit_ctx { + bool bus_isr; + bool ce_isr; + bool fb_isr; + bool fifo_isr; + bool gr_isr; + bool ltc_isr; + bool priv_ring_isr; + + u32 ce_isr_return; + u32 fifo_isr_return; + int gr_isr_return; +}; + +static struct unit_ctx u; + +static void reset_ctx(void) +{ + u.bus_isr = false; + u.ce_isr = false; + u.fb_isr = false; + u.fifo_isr = false; + u.gr_isr = false; + u.gr_isr_return = 0; + u.ltc_isr = false; + u.priv_ring_isr = false; +} + +/* + * Replacement functions that can be assigned to function pointers + */ +static int mock_get_device_info(struct gk20a *g, + struct nvgpu_device_info *dev_info, + u32 engine_type, u32 inst_id) +{ + if (engine_type == NVGPU_ENGINE_GRAPHICS) { + dev_info->intr_id = ACTIVE_GR_ID; + dev_info->engine_id = 0; + dev_info->engine_type = 0; + } else if (engine_type == NVGPU_ENGINE_LCE) { + dev_info->intr_id = ACTIVE_CE_ID; + dev_info->engine_id = 1; + dev_info->engine_type = 0x13; + dev_info->reset_id = ffs(mc_enable_ce2_enabled_f()) - 1; + } + + return 0; +} + +static bool mock_pbdma_find_for_runlist(struct gk20a *g, u32 runlist_id, + u32 *pbdma_id) +{ + return true; +} + +static u32 mock_get_num_engine_type_entries(struct gk20a *g, u32 engine_type) +{ + if (engine_type == NVGPU_ENGINE_LCE) { + return 1; + } + return 0; +} + +static void mock_bus_isr(struct gk20a *g) +{ + u.bus_isr = true; +} + +static void mock_ce_stall_isr(struct gk20a *g, u32 inst_id, u32 pri_base) +{ + u.ce_isr = true; +} + +static u32 mock_ce_nonstall_isr(struct gk20a *g, u32 inst_id, u32 pri_base) +{ + u.ce_isr = true; + return u.ce_isr_return; +} + +static void mock_fb_isr(struct gk20a *g) +{ + u.fb_isr = true; +} + +static void mock_fifo_stall_isr(struct gk20a *g) +{ + u.fifo_isr = true; +} + +static u32 mock_fifo_nonstall_isr(struct gk20a *g) +{ + u.fifo_isr = true; + return u.fifo_isr_return; +} + +static u32 mock_gr_nonstall_isr(struct gk20a *g) +{ + u.gr_isr = true; + return (u32)u.gr_isr_return; +} + +static int mock_gr_stall_isr(struct gk20a *g) +{ + u.gr_isr = true; + return u.gr_isr_return; +} + +static void mock_ltc_isr(struct gk20a *g, u32 ltc) +{ + u.ltc_isr = true; +} + +static void mock_priv_ring_isr(struct gk20a *g) +{ + u.priv_ring_isr = true; +} + +int test_setup_env(struct unit_module *m, + struct gk20a *g, void *args) +{ + /* Create mc register space */ + nvgpu_posix_io_init_reg_space(g); + if (nvgpu_posix_io_add_reg_space(g, MC_ADDR_SPACE_START, + MC_ADDR_SPACE_SIZE) != 0) { + unit_err(m, "%s: failed to create register space\n", + __func__); + return UNIT_FAIL; + } + /* Create fuse register space */ + if (nvgpu_posix_io_add_reg_space(g, GP10B_FUSE_REG_BASE, 0xfff) != 0) { + unit_err(m, "%s: failed to create register space\n", + __func__); + return UNIT_FAIL; + } + (void)nvgpu_posix_register_io(g, &test_reg_callbacks); + + nvgpu_posix_io_writel_reg_space(g, mc_boot_0_r(), MC_BOOT_0_GV11B); + nvgpu_posix_io_writel_reg_space(g, GP10B_FUSE_OPT_PRIV_SEC_EN, 0x0); + + if (nvgpu_detect_chip(g) != 0) { + unit_err(m, "%s: failed to init HAL\n", __func__); + return UNIT_FAIL; + } + + /* override HALs */ + g->ops.top.get_device_info = mock_get_device_info; + g->ops.pbdma.find_for_runlist = mock_pbdma_find_for_runlist; + g->ops.top.get_num_engine_type_entries = + mock_get_num_engine_type_entries; + g->ops.bus.isr = mock_bus_isr; + g->ops.ce.isr_stall = mock_ce_stall_isr; + g->ops.ce.isr_nonstall = mock_ce_nonstall_isr; + g->ops.fb.intr.isr = mock_fb_isr; + g->ops.fifo.intr_0_isr = mock_fifo_stall_isr; + g->ops.fifo.intr_1_isr = mock_fifo_nonstall_isr; + g->ops.gr.intr.stall_isr = mock_gr_stall_isr; + g->ops.gr.intr.nonstall_isr = mock_gr_nonstall_isr; + g->ops.ltc.intr.isr = mock_ltc_isr; + g->ops.priv_ring.isr = mock_priv_ring_isr; + + /* setup engines for getting interrupt info */ + g->fifo.g = g; + if (nvgpu_engine_setup_sw(g) != 0) { + unit_return_fail(m, "failed to setup engines\n"); + } + + /* setup LTC just enough */ + g->ltc = nvgpu_kzalloc(g, sizeof(struct nvgpu_ltc)); + if (g->ltc == NULL) { + unit_return_fail(m, "failed to alloc\n"); + } + g->ltc->ltc_count = 1; + + return UNIT_SUCCESS; +} + +int test_free_env(struct unit_module *m, struct gk20a *g, void *args) +{ + /* Free mc register space */ + nvgpu_posix_io_delete_reg_space(g, MC_ADDR_SPACE_START); + nvgpu_posix_io_delete_reg_space(g, GP10B_FUSE_REG_BASE); + + nvgpu_engine_cleanup_sw(g); + + nvgpu_kfree(g, g->ltc); + + return UNIT_SUCCESS; +} + +int test_unit_config(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 i; + u32 unit; + u32 val; + + /* clear regs */ + nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, STALL_DIS_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, NONSTALL_DIS_REG, 0x0); + + for (i = 0; i < NUM_MC_UNITS; i++) { + unit = mc_units[i].num; + + /* enable stall intr */ + nvgpu_mc_intr_stall_unit_config(g, unit, true); + val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG); + if (val != mc_units[i].bit) { + unit_return_fail(m, "failed to enable stall intr for unit %u val=0x%08x\n", + unit, val); + } + + /* disable stall intr */ + nvgpu_mc_intr_stall_unit_config(g, unit, false); + val = nvgpu_posix_io_readl_reg_space(g, STALL_DIS_REG); + if (val != mc_units[i].bit) { + unit_return_fail(m, "failed to disable stall intr for unit %u val=0x%08x\n", + unit, val); + } + + /* enable nonstall intr */ + nvgpu_mc_intr_nonstall_unit_config(g, unit, true); + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG); + if (val != mc_units[i].bit) { + unit_return_fail(m, "failed to enable nonstall intr for unit %u val=0x%08x\n", + unit, val); + } + + /* disable stall intr */ + nvgpu_mc_intr_nonstall_unit_config(g, unit, false); + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_DIS_REG); + if (val != mc_units[i].bit) { + unit_return_fail(m, "failed to disable nonstall intr for unit %u val=0x%08x\n", + unit, val); + } + } + + /* negative testing - invalid unit - stall */ + nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0); /* clear reg */ + nvgpu_mc_intr_stall_unit_config(g, U32_MAX, true); + val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG); + if (val != 0U) { + unit_return_fail(m, "Incorrectly enabled interrupt for invalid unit, val=0x%08x\n", + val); + } + + /* negative testing - invalid unit - nonstall */ + nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0); /* clear reg */ + nvgpu_mc_intr_nonstall_unit_config(g, U32_MAX, true); + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG); + if (val != 0U) { + unit_return_fail(m, "Incorrectly enabled interrupt for invalid unit, val=0x%08x\n", + val); + } + + return UNIT_SUCCESS; +} + +int test_pause_resume_mask(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 val; + u32 expected_stall_val = mc_intr_priv_ring_pending_f(); + u32 expected_nonstall_val = mc_intr_pbus_pending_f(); + void (*save_func)(struct gk20a *g); + + /* clear regs */ + nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, STALL_DIS_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, NONSTALL_DIS_REG, 0x0); + + /* cleanup anything from previous tests */ + g->mc.intr_mask_restore[0] = 0U; + g->mc.intr_mask_restore[1] = 0U; + + /* enable something to pause and resume */ + nvgpu_mc_intr_stall_unit_config(g, MC_INTR_UNIT_PRIV_RING, true); + nvgpu_mc_intr_nonstall_unit_config(g, MC_INTR_UNIT_BUS, true); + + /* pause stall */ + nvgpu_mc_intr_stall_pause(g); + val = nvgpu_posix_io_readl_reg_space(g, STALL_DIS_REG); + if (val != U32_MAX) { + unit_return_fail(m, "failed to pause stall intr\n"); + } + + /* pause nonstall */ + nvgpu_mc_intr_nonstall_pause(g); + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_DIS_REG); + if (val != U32_MAX) { + unit_return_fail(m, "failed to pause nonstall intr\n"); + } + + /* resume stall */ + nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0); + nvgpu_mc_intr_stall_resume(g); + val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG); + if (val != expected_stall_val) { + unit_return_fail(m, "failed to resume stall intr\n"); + } + + /* resume nonstall */ + nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0); + nvgpu_mc_intr_nonstall_resume(g); + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG); + if (val != expected_nonstall_val) { + unit_return_fail(m, "failed to resume nonstall intr\n"); + } + + /* clear regs */ + nvgpu_posix_io_writel_reg_space(g, STALL_DIS_REG, 0x0); + nvgpu_posix_io_writel_reg_space(g, NONSTALL_DIS_REG, 0x0); + + /* mask all */ + nvgpu_mc_intr_mask(g); + val = nvgpu_posix_io_readl_reg_space(g, STALL_DIS_REG); + if (val != U32_MAX) { + unit_return_fail(m, "failed to mask stall intr\n"); + } + val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_DIS_REG); + if (val != U32_MAX) { + unit_return_fail(m, "failed to mask nonstall intr\n"); + } + + /* make this HAL NULL for branch coverage */ + save_func = g->ops.mc.intr_mask; + g->ops.mc.intr_mask = NULL; + nvgpu_mc_intr_mask(g); + g->ops.mc.intr_mask = save_func; + + return UNIT_SUCCESS; +} + +static void switch_ce_engine_type(struct nvgpu_engine_info *info) +{ + if (info->engine_enum == NVGPU_ENGINE_ASYNC_CE) { + info->engine_enum = NVGPU_ENGINE_GRCE; + } else if (info->engine_enum == NVGPU_ENGINE_GRCE) { + info->engine_enum = NVGPU_ENGINE_ASYNC_CE; + } else { + BUG(); + } +} + +int test_intr_stall(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 i, pend, val; + + for (i = 0; i < 32; i++) { + pend = (1 << i); + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, pend); + val = g->ops.mc.intr_stall(g); + if (val != pend) { + unit_return_fail(m, "incorrect stall value returned\n"); + } + } + + return UNIT_SUCCESS; +} + +int test_is_stall_and_eng_intr_pending(struct unit_module *m, struct gk20a *g, + void *args) +{ + u32 act_eng_id = 0; /* GR engine */ + u32 eng_intr_pending = 0; + u32 intrs_pending = 0; + u32 expected_eng_intr_pending = 0; + bool result; + unsigned int i; + + /* test with nothing pending */ + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, 0); + result = g->ops.mc.is_stall_and_eng_intr_pending(g, act_eng_id, + &eng_intr_pending); + if (result) { + unit_return_fail(m, "incorrect value returned\n"); + } + + /* test with everything pending */ + for (i = 0U; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + if (mc_units[i].num == MC_INTR_UNIT_GR) { + expected_eng_intr_pending = mc_units[i].bit; + } + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + result = g->ops.mc.is_stall_and_eng_intr_pending(g, act_eng_id, + &eng_intr_pending); + if (!result || (eng_intr_pending != expected_eng_intr_pending)) { + unit_return_fail(m, "incorrect value returned\n"); + } + + return UNIT_SUCCESS; +} + +int test_isr_stall(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 intrs_pending = 0; + u32 i; + bool (*save_intr_hub_pending)(struct gk20a *g, u32 intr); + + /* for branch coverage, test with nothing pending */ + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, 0); + reset_ctx(); + g->ops.mc.isr_stall(g); + if (u.bus_isr || u.ce_isr || u.fb_isr || u.fifo_isr || u.gr_isr || + u.priv_ring_isr) { + unit_return_fail(m, "unexpected ISR called\n"); + } + + /* setup regs for basic test with all units intr pending */ + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + nvgpu_posix_io_writel_reg_space(g, mc_intr_ltc_r(), 1U); + reset_ctx(); + g->ops.mc.isr_stall(g); + if (!u.bus_isr || !u.ce_isr || !u.fb_isr || !u.fifo_isr || !u.gr_isr || + !u.priv_ring_isr) { + unit_return_fail(m, "not all ISRs called\n"); + } + + /* for branch coverage set this HAL to NULL */ + save_intr_hub_pending = g->ops.mc.is_intr_hub_pending; + g->ops.mc.is_intr_hub_pending = NULL; + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + reset_ctx(); + g->ops.mc.isr_stall(g); + if (u.fb_isr) { + unit_return_fail(m, "unexpected ISR called\n"); + } + g->ops.mc.is_intr_hub_pending = save_intr_hub_pending; + + /* for branch coverage return error from GR ISR */ + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + reset_ctx(); + u.gr_isr_return = -1; + g->ops.mc.isr_stall(g); + + /* for branch coverage set this HAL to NULL */ + g->ops.ce.isr_stall = NULL; + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + reset_ctx(); + g->ops.mc.isr_stall(g); + g->ops.ce.isr_stall = mock_ce_stall_isr; + + /* for branch coverage set CE engine to other type */ + switch_ce_engine_type(&g->fifo.engine_info[1]); + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + reset_ctx(); + g->ops.mc.isr_stall(g); + if (!u.ce_isr) { + unit_return_fail(m, "ISR not called\n"); + } + + /* + * for branch coverage set LTC intr in main intr reg, but not ltc + * intr reg + */ + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending); + nvgpu_posix_io_writel_reg_space(g, mc_intr_ltc_r(), 0U); + reset_ctx(); + g->ops.mc.isr_stall(g); + if (u.ltc_isr) { + unit_return_fail(m, "unexpected ISR called\n"); + } + + return UNIT_SUCCESS; +} + +int test_is_intr1_pending(struct unit_module *m, struct gk20a *g, void *args) +{ + struct match_struct { + enum nvgpu_unit unit; + u32 mask; + bool expect; + }; + const struct match_struct match_table[] = { + { NVGPU_UNIT_FIFO, ~mc_enable_pfifo_enabled_f(), false }, + { NVGPU_UNIT_FIFO, mc_enable_pfifo_enabled_f(), true }, + { INVALID_UNIT, 0x0, false }, + }; + unsigned int i; + bool val; + + for (i = 0; i < ARRAY_SIZE(match_table); i++) { + val = g->ops.mc.is_intr1_pending(g, match_table[i].unit, + match_table[i].mask); + if (val != match_table[i].expect) { + unit_return_fail(m, "incorrect stall value returned\n"); + } + } + + return UNIT_SUCCESS; +} + +int test_isr_nonstall(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 intrs_pending = 0; + u32 i; + u32 val; + + /* for branch coverage, test with nothing pending */ + nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, 0); + reset_ctx(); + val = g->ops.mc.isr_nonstall(g); + if (u.bus_isr || u.ce_isr || u.fb_isr || u.fifo_isr || u.gr_isr || + u.priv_ring_isr) { + unit_return_fail(m, "unexpected ISR called\n"); + } + + /* setup regs for basic test with all units intr pending */ + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, intrs_pending); + reset_ctx(); + u.ce_isr_return = 0x1; + u.fifo_isr_return = 0x2; + u.gr_isr_return = 0x4; + val = g->ops.mc.isr_nonstall(g); + if (!u.ce_isr || !u.fifo_isr || !u.gr_isr) { + unit_return_fail(m, "not all ISRs called\n"); + } + if (val != 0x7) { + unit_return_fail(m, "incorrect ops returned 0x%08x\n", val); + } + + /* for branch coverage set this HAL to NULL */ + g->ops.ce.isr_nonstall = NULL; + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, intrs_pending); + reset_ctx(); + g->ops.mc.isr_nonstall(g); + g->ops.ce.isr_nonstall = mock_ce_nonstall_isr; + + /* for branch coverage set CE engine to the opposite type */ + switch_ce_engine_type(&g->fifo.engine_info[1]); + for (i = 0; i < NUM_MC_UNITS; i++) { + intrs_pending |= mc_units[i].bit; + } + nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, intrs_pending); + reset_ctx(); + g->ops.mc.isr_nonstall(g); + if (!u.ce_isr) { + unit_return_fail(m, "ISR not called\n"); + } + + return UNIT_SUCCESS; +} + +int test_enable_disable_reset(struct unit_module *m, struct gk20a *g, void *args) +{ + u32 units = (g->ops.mc.reset_mask(g, NVGPU_UNIT_FIFO) | + g->ops.mc.reset_mask(g, NVGPU_UNIT_GRAPH) | + g->ops.mc.reset_mask(g, NVGPU_UNIT_BLG) | + mc_enable_ce2_enabled_f()); + u32 val; + + /* test enable */ + nvgpu_posix_io_writel_reg_space(g, mc_enable_r(), 0); + g->ops.mc.enable(g, units); + val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r()); + if (val != units) { + unit_return_fail(m, "failed to reset units val=0x%08x\n", val); + } + + /* test disable */ + g->ops.mc.disable(g, units); + val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r()); + if (val != 0U) { + unit_return_fail(m, "failed to reset units val=0x%08x\n", val); + } + + /* test reset */ + nvgpu_posix_io_writel_reg_space(g, mc_enable_r(), units); + g->ops.mc.reset(g, units); + val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r()); + if (val != units) { + unit_return_fail(m, "failed to reset units val=0x%08x\n", val); + } + + /* for branch coverage, do not include CE's */ + units = NVGPU_UNIT_FIFO | NVGPU_UNIT_GRAPH; + nvgpu_posix_io_writel_reg_space(g, mc_enable_r(), units); + g->ops.mc.reset(g, units); + val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r()); + if (val != units) { + unit_return_fail(m, "failed to reset units val=0x%08x\n", val); + } + + return UNIT_SUCCESS; +} + +int test_reset_mask(struct unit_module *m, struct gk20a *g, void *args) +{ + struct match_struct { + enum nvgpu_unit unit; + u32 mask; + }; + const struct match_struct match_table[] = { + { NVGPU_UNIT_FIFO, mc_enable_pfifo_enabled_f() }, + { NVGPU_UNIT_PERFMON, mc_enable_perfmon_enabled_f() }, + { NVGPU_UNIT_GRAPH, mc_enable_pgraph_enabled_f() }, + { NVGPU_UNIT_BLG, mc_enable_blg_enabled_f() }, + }; + unsigned int i; + u32 val; + + for (i = 0U; i < ARRAY_SIZE(match_table); i++) { + val = g->ops.mc.reset_mask(g, match_table[i].unit); + if (val != match_table[i].mask) { + unit_return_fail(m, "incorrect mask returned\n"); + } + } + + /* pass invalid unit for branch coverage */ + val = g->ops.mc.reset_mask(g, INVALID_UNIT); + if (val != 0U) { + unit_return_fail(m, "incorrect mask returned\n"); + } + + return UNIT_SUCCESS; +} + +int test_wait_for_deferred_interrupts(struct unit_module *m, struct gk20a *g, + void *args) +{ + struct nvgpu_posix_fault_inj *cond_fi = + nvgpu_cond_get_fault_injection(); + + nvgpu_cond_init(&g->mc.sw_irq_stall_last_handled_cond); + nvgpu_cond_init(&g->mc.sw_irq_nonstall_last_handled_cond); + + /* immediate completion */ + nvgpu_atomic_set(&g->mc.hw_irq_stall_count, 0); + nvgpu_atomic_set(&g->mc.sw_irq_stall_last_handled, 0); + nvgpu_atomic_set(&g->mc.hw_irq_nonstall_count, 0); + nvgpu_atomic_set(&g->mc.sw_irq_nonstall_last_handled, 0); + nvgpu_wait_for_deferred_interrupts(g); + + /* cause timeout */ + nvgpu_posix_enable_fault_injection(cond_fi, true, 0); + + /* wait on stall until timeout for branch coverage */ + nvgpu_atomic_set(&g->mc.hw_irq_stall_count, 1); + nvgpu_atomic_set(&g->mc.sw_irq_stall_last_handled, 0); + nvgpu_atomic_set(&g->mc.hw_irq_nonstall_count, 0); + nvgpu_atomic_set(&g->mc.sw_irq_nonstall_last_handled, 0); + nvgpu_wait_for_deferred_interrupts(g); + + /* wait on nonstall until timeout for branch coverage */ + nvgpu_atomic_set(&g->mc.hw_irq_stall_count, 0); + nvgpu_atomic_set(&g->mc.sw_irq_stall_last_handled, 0); + nvgpu_atomic_set(&g->mc.hw_irq_nonstall_count, 1); + nvgpu_atomic_set(&g->mc.sw_irq_nonstall_last_handled, 0); + nvgpu_wait_for_deferred_interrupts(g); + + return UNIT_SUCCESS; +} + +struct unit_module_test mc_tests[] = { + UNIT_TEST(mc_setup_env, test_setup_env, NULL, 0), + UNIT_TEST(unit_config, test_unit_config, NULL, 0), + UNIT_TEST(pause_resume_mask, test_pause_resume_mask, NULL, 0), + UNIT_TEST(intr_stall, test_intr_stall, NULL, 0), + UNIT_TEST(intr_is_stall_and_eng_intr_pending, + test_is_stall_and_eng_intr_pending, NULL, 0), + UNIT_TEST(isr_stall, test_isr_stall, NULL, 0), + UNIT_TEST(isr_nonstall, test_isr_nonstall, NULL, 0), + UNIT_TEST(is_intr1_pending, test_is_intr1_pending, NULL, 0), + UNIT_TEST(enable_disable_reset, test_enable_disable_reset, NULL, 0), + UNIT_TEST(reset_mask, test_reset_mask, NULL, 0), + UNIT_TEST(wait_for_deferred_interrupts, test_wait_for_deferred_interrupts, NULL, 0), + UNIT_TEST(mc_free_env, test_free_env, NULL, 0), +}; + +UNIT_MODULE(mc, mc_tests, UNIT_PRIO_NVGPU_TEST); diff --git a/userspace/units/mc/nvgpu-mc.h b/userspace/units/mc/nvgpu-mc.h new file mode 100644 index 000000000..27445f26d --- /dev/null +++ b/userspace/units/mc/nvgpu-mc.h @@ -0,0 +1,358 @@ +/* + * 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_MC_H +#define UNIT_NVGPU_MC_H + +struct gk20a; +struct unit_module; + +/** @addtogroup SWUTS-mc + * @{ + * + * Software Unit Test Specification for MC + */ + +/** + * Test specification for: test_setup_env + * + * Description: Do basic setup before starting other tests. + * + * Test Type: Other (setup) + * + * Input: None + * + * Steps: + * - Initialize reg spaces used by tests. + * - Override HALs for other dependent units. + * - Do minimal initialization for engines and ltc units. + * + * Output: + * - UNIT_FAIL if encounters an error creating reg space + * - UNIT_SUCCESS otherwise + */ +int test_setup_env(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_free_env + * + * Description: Do basic setup before starting other tests. + * + * Test Type: Other (setup) + * + * Input: test_setup_env has run. + * + * Steps: + * - Free reg spaces. + * - Cleanup engine setup. + * - Free ltc memory. + * + * Output: UNIT_SUCCESS always. + */ +int test_free_env(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_unit_config + * + * Description: Validate function of nvgpu_mc_intr_stall_unit_config and + * nvgpu_mc_intr_nonstall_unit_config. + * + * Test Type: Feature based + * + * Targets: nvgpu_mc_intr_stall_unit_config, nvgpu_mc_intr_nonstall_unit_config + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Set each of the mock registers for enabling & disabling the stall & + * non-stall interrupts to 0. + * - Loop through table of units: + * - Call nvgpu_mc_intr_stall_unit_config for the unit to enable the stall + * interrupt. + * - Verify the stall interrupt enable register has the bit set for the unit. + * - Call nvgpu_mc_intr_stall_unit_config for the unit to disable the interrupt. + * - Verify the stall interrupt disable register has the bit set for the unit. + * - Call nvgpu_mc_intr_nonstall_unit_config for the unit to enable the + * non-stall interrupt. + * - Verify the non-stall interrupt enable register has the bit set for the unit. + * - Call nvgpu_mc_intr_nonstall_unit_config for the unit to disable the interrupt. + * - Verify the non-stall interrupt disable register has the bit set for the unit. + * - Clear the stall enable register. + * - For negative testing, call nvgpu_mc_intr_stall_unit_config() with an + * invalid unit number, and verify no bits are set in the stall interrupt + * enable register. + * - Clear the stall enable register. + * - For negative testing, call nvgpu_mc_intr_nonstall_unit_config() with an + * invalid unit number, and verify no bits are set in the non-stall interrupt + * enable register. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_unit_config(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_pause_resume_mask + * + * Description: Validate function for pausing, resuming, and masking interrupts. + * + * Test Type: Feature based + * + * Targets: nvgpu_mc_intr_stall_pause, nvgpu_mc_intr_stall_resume, + * nvgpu_mc_intr_nonstall_pause, nvgpu_mc_intr_nonstall_resume, + * nvgpu_mc_intr_mask + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Clear each of the mock registers for enabling & disabling the stall & + * non-stall interrupts. + * - Clear mc state regs for active interrupts. + * - Enable interupts so they can be paused and resumed. + * - Pause the interrupts. + * - Verify all the bits were written in the stall and non-stall interrupt + * disable registers. + * - Resume the interrupts. + * - Verify the correct values are in the stall and non-stall interrupt enable + * registers. + * - Clear the stall and non-stall disable registers. + * - Mask the interrupts. + * - Verify all the bits were written in the stall and non-stall interrupt + * disable registers. + * - For branch coverage, temporarily set the g->ops.mc.intr_mask HAL to NULL. + * - Mask the interrupts. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_pause_resume_mask(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_intr_stall + * + * Description: Validate function mc_gp10b_intr_stall which returns the pending + * interrupts. + * + * Test Type: Feature based + * + * Targets: mc_gp10b_intr_stall + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Loop through setting each bit individually in the stall interrupt pending + * register: + * - For iteration, call the HAL and verify the correct value is returned. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_intr_stall(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_is_stall_and_eng_intr_pending + * + * Description: Validate function of HAL gv11b_mc_is_stall_and_eng_intr_pending. + * + * Test Type: Feature based + * + * Targets: gv11b_mc_is_stall_and_eng_intr_pending + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Clear the stall interrupt pending register. + * - Call the HAL API and verify it returns false since nothing is pending. + * - Set all interrupts pending in the stall interrupt pending register. + * - Call the HAL API and verify it returns true and the correct pending mask. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_is_stall_and_eng_intr_pending(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_isr_stall + * + * Description: Validate handling of the stall interrupts by the stall interrupt + * service routine. + * + * Test Type: Feature based + * + * Targets: mc_gp10b_isr_stall + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Clear the stall interrupt pending register. + * - Call the stall ISR. + * - Verify none of the mock unit ISRs (for bus, ce, fb, etc) are called. + * - Set all interrupts pending in the stall interrupt pending register. + * - Call the stall ISR. + * - Verify all of the mock unit ISRs are called. + * - For branch coverage, set the HAL pointer g->ops.mc.is_intr_hub_pending to + * NULL. + * - Call the stall ISR. No exception should occur. + * - For branch coverage, configure the mock GR ISR to return an error. + * - Call the stall ISR. No exception should occur. + * - For branch coverage, configure the mock CE ISR pointer to NULL. + * - Call the stall ISR. No exception should occur. + * - For branch coverage, configure the active CE engine to the other type. + * - Call the stall ISR. No exception should occur. + * - For branch coverage, enable the LTC interupt pending in main MC pending + * register, MC_INTR, but disable the LTC interrupt pending in the LTC-specific + * register, MC_INTR_LTC. + * - Call the stall ISR. + * - Verify the mock LTC ISR was not called. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_isr_stall(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_isr_nonstall + * + * Description: Validate handling of the stall interrupts by the non-stall + * interrupt service routine. + * + * Test Type: Feature based + * + * Targets: gm20b_mc_isr_nonstall + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Clear the non-stall interrupt pending register. + * - Call the non-stall ISR. + * - Verify none of the mock unit ISRs (for bus, ce, fb, etc) are called. + * - Set all interrupts pending in the non-stall interrupt pending register. + * - Call the non-stall ISR. + * - Verify all of the mock unit ISRs are called and the correct ops are returned. + * - For branch coverage, configure the mock CE ISR pointer to NULL. + * - Call the non-stall ISR. No exception should occur. + * - For branch coverage, configure the active CE engine to the other type. + * - Call the non-stall ISR. No exception should occur. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_isr_nonstall(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_is_intr1_pending + * + * Description: Validate functionality of mc_gp10b_is_intr1_pending. + * + * Test Type: Feature based + * + * Targets: mc_gp10b_is_intr1_pending + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Call the HAL API, requesting if the FIFO Unit is pending, passing in a + * register mask that does not have that Unit pending. Verify false is + * returned. + * - Call the HAL API, requesting if the FIFO Unit is pending, passing in a + * register mask that does have that Unit pending. Verify true is returned. + * - Call the HAL API passing in an invalid unit number. Verify false is + * returned. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_is_intr1_pending(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_enable_disable_reset + * + * Description: Validate functionality of functions for enabling, disabling, + * and reseting units. + * + * Test Type: Feature based + * + * Targets: gm20b_mc_enable, gm20b_mc_disable, gm20b_mc_reset + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Call the enable HAL API to enable units. + * - Read the MC_ENABLE reg to verify the units were enabled. + * - Call the disable HAL API to disable units. + * - Read the MC_ENABLE reg to verify the units were disabled. + * - Call the reset HAL API to reset units. + * - Read the MC_ENABLE reg to verify the units were re-enabled. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_enable_disable_reset(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_reset_mask + * + * Description: Validate functionality of HAL to get reset mask for a unit. + * + * Test Type: Feature based + * + * Targets: gm20b_mc_reset_mask + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Call the enable HAL API for a number of units and verify the correct + * mask is returned. + * - For branch coverage pass in an invalid Unit number, and verify the mask + * returned is 0. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_reset_mask(struct unit_module *m, struct gk20a *g, void *args); + +/** + * Test specification for: test_wait_for_deferred_interrupts + * + * Description: Validate functionality of HAL to get reset mask for a unit. + * + * Test Type: Feature based + * + * Targets: nvgpu_wait_for_deferred_interrupts + * + * Input: test_setup_env must have been run. + * + * Steps: + * - Initialize cond structures required by the API. + * - Set the irq count states in the gk20a struct to 0 to cause immediate + * completion. + * - Call the API. + * - Enable cond fault injection to simulate a timeouts. + * - Set the irq count states in the gk20a struct to simulate pending stall + * interrupts. + * - Call the API. + * - Set the irq count states in the gk20a struct to simulate pending non-stall + * interrupts. + * + * Output: Returns PASS if expected result is met, FAIL otherwise. + */ +int test_wait_for_deferred_interrupts(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * @} + */ + +#endif /* UNIT_NVGPU_CE_H */ \ No newline at end of file