From 50af902b71fdc93cddbe9ed676ebf483c93d542e Mon Sep 17 00:00:00 2001 From: Vedashree Vidwans Date: Fri, 27 Dec 2019 09:46:50 -0800 Subject: [PATCH] gpu: nvgpu: unit: fifo: preempt-gv11b unit test This unit test covers all nvgpu.hal.fifo.preempt.gv11b module lines and branches. Jira NVGPU-4675 Change-Id: I5b7104c242e07fc61c4d155de3c0003b2bea7dfe Signed-off-by: Vedashree Vidwans Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2274044 Reviewed-by: mobile promotions Tested-by: mobile promotions --- Makefile.umbrella.tmk | 1 + drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 5 + userspace/Makefile.sources | 1 + userspace/SWUTS.h | 1 + userspace/SWUTS.sources | 1 + userspace/required_tests.json | 48 ++ userspace/units/fifo/preempt/gv11b/Makefile | 32 + .../fifo/preempt/gv11b/Makefile.interface.tmk | 35 + .../units/fifo/preempt/gv11b/Makefile.tmk | 40 + .../fifo/preempt/gv11b/nvgpu-preempt-gv11b.c | 681 ++++++++++++++++++ .../fifo/preempt/gv11b/nvgpu-preempt-gv11b.h | 161 +++++ 11 files changed, 1006 insertions(+) create mode 100644 userspace/units/fifo/preempt/gv11b/Makefile create mode 100644 userspace/units/fifo/preempt/gv11b/Makefile.interface.tmk create mode 100644 userspace/units/fifo/preempt/gv11b/Makefile.tmk create mode 100644 userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.c create mode 100644 userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.h diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index 105befcf1..8263da4f1 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -103,6 +103,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma/gv11b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma/gm20b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma/gp10b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/preempt +NV_REPOSITORY_COMPONENTS += userspace/units/fifo/preempt/gv11b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/ramfc/gp10b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/ramfc/gv11b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/ramin/gk20a diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index c2e61dc2f..777bc0017 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -147,7 +147,12 @@ gv11b_fifo_intr_0_enable gv11b_fifo_intr_0_isr gv11b_fifo_intr_set_recover_mask gv11b_fifo_intr_unset_recover_mask +gv11b_fifo_is_preempt_pending gv11b_fifo_mmu_fault_id_to_pbdma_id +gv11b_fifo_preempt_channel +gv11b_fifo_preempt_poll_pbdma +gv11b_fifo_preempt_runlists_for_rc +gv11b_fifo_preempt_trigger gv11b_fifo_preempt_tsg gv11b_get_litter_value gv11b_gpu_phys_addr diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index db04e6525..3328e7eab 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -113,6 +113,7 @@ UNITS := \ $(UNIT_SRC)/fifo/pbdma/gp10b \ $(UNIT_SRC)/fifo/pbdma/gv11b \ $(UNIT_SRC)/fifo/preempt \ + $(UNIT_SRC)/fifo/preempt/gv11b \ $(UNIT_SRC)/fifo/ramfc/gp10b \ $(UNIT_SRC)/fifo/ramfc/gv11b \ $(UNIT_SRC)/fifo/ramin/gk20a \ diff --git a/userspace/SWUTS.h b/userspace/SWUTS.h index 74e488c0c..a610e539f 100644 --- a/userspace/SWUTS.h +++ b/userspace/SWUTS.h @@ -58,6 +58,7 @@ * - @ref SWUTS-fifo-pbdma-gp10b * - @ref SWUTS-fifo-pbdma-gv11b * - @ref SWUTS-fifo-preempt + * - @ref SWUTS-fifo-preempt-gv11b * - @ref SWUTS-fifo-ramfc-gp10b * - @ref SWUTS-fifo-ramfc-gv11b * - @ref SWUTS-fifo-ramin-gk20a diff --git a/userspace/SWUTS.sources b/userspace/SWUTS.sources index 7860fb786..d49c5ebdb 100644 --- a/userspace/SWUTS.sources +++ b/userspace/SWUTS.sources @@ -34,6 +34,7 @@ INPUT += ../../../userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-status-gm20b.h INPUT += ../../../userspace/units/fifo/pbdma/gp10b/nvgpu-pbdma-gp10b.h INPUT += ../../../userspace/units/fifo/pbdma/gv11b/nvgpu-pbdma-gv11b.h INPUT += ../../../userspace/units/fifo/preempt/nvgpu-preempt.h +INPUT += ../../../userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.h INPUT += ../../../userspace/units/fifo/ramfc/gp10b/nvgpu-ramfc-gp10b.h INPUT += ../../../userspace/units/fifo/ramfc/gv11b/nvgpu-ramfc-gv11b.h INPUT += ../../../userspace/units/fifo/ramin/gk20a/ramin-gk20a-fusa.h diff --git a/userspace/required_tests.json b/userspace/required_tests.json index 159e5b25f..331796136 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -3107,6 +3107,54 @@ "unit": "nvgpu_preempt", "test_level": 0 }, + { + "test": "test_fifo_init_support", + "case": "init_support", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_is_preempt_pending", + "case": "is_preempt_pending", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_preempt_channel", + "case": "preempt_channel", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_preempt_poll_pbdma", + "case": "preempt_poll_pbdma", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_preempt_runlists_for_rc", + "case": "preempt_runlists_for_rc", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_preempt_trigger", + "case": "preempt_trigger", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_gv11b_fifo_preempt_tsg", + "case": "preempt_tsg", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, + { + "test": "test_fifo_remove_support", + "case": "remove_support", + "unit": "nvgpu_preempt_gv11b", + "test_level": 0 + }, { "test": "test_flat_gen", "case": "flat", diff --git a/userspace/units/fifo/preempt/gv11b/Makefile b/userspace/units/fifo/preempt/gv11b/Makefile new file mode 100644 index 000000000..ac542ac43 --- /dev/null +++ b/userspace/units/fifo/preempt/gv11b/Makefile @@ -0,0 +1,32 @@ +# Copyright (c) 2020, 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-preempt-gv11b.o +MODULE = nvgpu-preempt-gv11b + +LIB_PATHS += -lnvgpu-fifo-common +include ../../../Makefile.units + +lib$(MODULE).so: fifo + +fifo: + $(MAKE) -C ../.. diff --git a/userspace/units/fifo/preempt/gv11b/Makefile.interface.tmk b/userspace/units/fifo/preempt/gv11b/Makefile.interface.tmk new file mode 100644 index 000000000..e9595daac --- /dev/null +++ b/userspace/units/fifo/preempt/gv11b/Makefile.interface.tmk @@ -0,0 +1,35 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2020, 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. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=nvgpu-preempt-gv11b + +include $(NV_SOURCE)/kernel/nvgpu/userspace/units/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/fifo/preempt/gv11b/Makefile.tmk b/userspace/units/fifo/preempt/gv11b/Makefile.tmk new file mode 100644 index 000000000..20f48b9a1 --- /dev/null +++ b/userspace/units/fifo/preempt/gv11b/Makefile.tmk @@ -0,0 +1,40 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2020, 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. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME = nvgpu-preempt-gv11b +NVGPU_UNIT_SRCS = nvgpu-preempt-gv11b.c + +NVGPU_UNIT_INTERFACE_DIRS := \ + $(NV_SOURCE)/kernel/nvgpu/userspace/units/fifo \ + $(NV_SOURCE)/kernel/nvgpu/drivers/gpu/nvgpu + +include $(NV_SOURCE)/kernel/nvgpu/userspace/units/Makefile.units.common.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.c b/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.c new file mode 100644 index 000000000..c629b01dd --- /dev/null +++ b/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.c @@ -0,0 +1,681 @@ +/* + * Copyright (c) 2020, 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 +#include + +#include + +#include "hal/fifo/preempt_gv11b.h" + +#include "../../nvgpu-fifo-common.h" +#include "nvgpu-preempt-gv11b.h" + +#ifdef PREEMPT_GV11B_UNIT_DEBUG +#undef unit_verbose +#define unit_verbose unit_info +#else +#define unit_verbose(unit, msg, ...) \ + do { \ + if (0) { \ + unit_info(unit, msg, ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +#define branches_str test_fifo_flags_str +#define pruned test_fifo_subtest_pruned + +struct stub_ctx { + bool result; + struct nvgpu_pbdma_status_info pbdma_st; + u32 eng_stat; + u32 eng_intr_pending; +}; + +struct stub_ctx stub; + +struct preempt_gv11b_unit_ctx { + u32 branches; +}; + +static struct preempt_gv11b_unit_ctx unit_ctx; + +static void subtest_setup(u32 branches) +{ + unit_ctx.branches = branches; +} + + +#define F_PREEMPT_TRIGGER_TSG BIT(0) +#define F_PREEMPT_TRIGGER_LAST BIT(1) + +static const char *f_preempt_trigger[] = { + "preempt_trigger_tsg", +}; + +int test_gv11b_fifo_preempt_trigger(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_FAIL; + u32 branches = 0U; + u32 orig_reg_val = nvgpu_readl(g, fifo_preempt_r()); + u32 expected_reg_val; + + for (branches = 0U; branches < F_PREEMPT_TRIGGER_LAST; branches++) { + unit_verbose(m, "%s branches=%s\n", + __func__, branches_str(branches, f_preempt_trigger)); + + if (branches & F_PREEMPT_TRIGGER_TSG) { + gv11b_fifo_preempt_trigger(g, 5U, ID_TYPE_TSG); + expected_reg_val = fifo_preempt_id_f(5U) | + fifo_preempt_type_tsg_f(); + unit_assert(expected_reg_val == + nvgpu_readl(g, fifo_preempt_r()), goto done); + nvgpu_writel(g, fifo_preempt_r(), orig_reg_val); + } else { + gv11b_fifo_preempt_trigger(g, 5U, ID_TYPE_CHANNEL); + unit_assert(orig_reg_val == + nvgpu_readl(g, fifo_preempt_r()), goto done); + } + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_preempt_trigger)); + } + + return ret; +} + +int test_gv11b_fifo_preempt_runlists_for_rc(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + u32 runlist_mask; + u32 reg_val; + + nvgpu_runlist_lock_active_runlists(g); + runlist_mask = nvgpu_runlist_get_runlists_mask(g, 0U, ID_TYPE_UNKNOWN, + 0U, 0U); + reg_val = nvgpu_readl(g, fifo_runlist_preempt_r()); + + gv11b_fifo_preempt_runlists_for_rc(g, runlist_mask); + unit_assert(nvgpu_readl(g, fifo_runlist_preempt_r()) == + (reg_val | runlist_mask), goto done); + + nvgpu_runlist_unlock_active_runlists(g); + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s failed\n", __func__); + } + + return ret; +} + +static bool stub_pbdma_handle_intr(struct gk20a *g, u32 pbdma_id, + u32 *error_notifier, + struct nvgpu_pbdma_status_info *pbdma_status) +{ + pbdma_status->chsw_status = stub.pbdma_st.chsw_status; + pbdma_status->id = stub.pbdma_st.id; + pbdma_status->next_id = stub.pbdma_st.next_id; + + return false; +} + +#define F_PREEMPT_POLL_PBDMA_TIMEOUT_INIT_FAIL BIT(0) +#define F_PREEMPT_POLL_PBDMA_PLATFORM_SILICON BIT(1) +#define F_PREEMPT_POLL_PBDMA_CHSW_IS_VALID BIT(2) +#define F_PREEMPT_POLL_PBDMA_CHSW_IS_SAVE BIT(3) +#define F_PREEMPT_POLL_PBDMA_CHSW_IS_LOAD BIT(4) +#define F_PREEMPT_POLL_PBDMA_CHSW_IS_SWITCH BIT(5) +#define F_PREEMPT_POLL_PBDMA_STATUS_ID_IS_TSGID BIT(6) +#define F_PREEMPT_POLL_PBDMA_STATUS_NEXT_ID_IS_TSGID BIT(7) +#define F_PREEMPT_POLL_PRE_SI_RETRIES BIT(8) +#define F_PREEMPT_POLL_PBDMA_LAST BIT(9) + +static const char *f_preempt_poll_pbdma[] = { + "timeout_init_fail", + "platform_silicon", + "chsw_is_valid", + "chsw_is_save", + "chsw_is_load", + "chsw_is_switch", + "status_id_is_tsgid", + "status_next_id_is_tsgid", +}; + +int test_gv11b_fifo_preempt_poll_pbdma(struct unit_module *m, struct gk20a *g, + void *args) +{ + u32 tsgid = 0U; + int ret = UNIT_FAIL; + int err; + u32 branches = 0U; + u32 prune = F_PREEMPT_POLL_PBDMA_TIMEOUT_INIT_FAIL | + F_PREEMPT_POLL_PRE_SI_RETRIES; + struct gpu_ops gops = g->ops; + struct nvgpu_posix_fault_inj *timers_fi; + struct nvgpu_os_posix *p = nvgpu_os_posix_from_gk20a(g); + + timers_fi = nvgpu_timers_get_fault_injection(); + g->ops.pbdma.handle_intr = stub_pbdma_handle_intr; + + for (branches = 0U; branches < F_PREEMPT_POLL_PBDMA_LAST; branches++) { + if (pruned(branches, prune)) { + unit_verbose(m, "%s branches=%s (pruned)\n", __func__, + branches_str(branches, + f_preempt_poll_pbdma)); + continue; + } + subtest_setup(branches); + unit_verbose(m, "%s branches=%s\n", + __func__, branches_str(branches, f_preempt_poll_pbdma)); + + nvgpu_posix_enable_fault_injection(timers_fi, + branches & F_PREEMPT_POLL_PBDMA_TIMEOUT_INIT_FAIL ? + true : false, 0); + + if (branches & F_PREEMPT_POLL_PRE_SI_RETRIES) { + /* Timeout should not expire */ + nvgpu_posix_enable_fault_injection(timers_fi, true, + PREEMPT_PENDING_POLL_PRE_SI_RETRIES + 4U); + + /* Force pbdma status = chsw_valid */ + branches |= F_PREEMPT_POLL_PBDMA_CHSW_IS_VALID; + /* Force tsgid = pbdma_status id */ + branches |= F_PREEMPT_POLL_PBDMA_STATUS_ID_IS_TSGID; + } + + p->is_silicon = + branches & F_PREEMPT_POLL_PBDMA_PLATFORM_SILICON ? + true : false; + + if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_VALID) { + stub.pbdma_st.chsw_status = + NVGPU_PBDMA_CHSW_STATUS_VALID; + } else if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_SAVE) { + stub.pbdma_st.chsw_status = + NVGPU_PBDMA_CHSW_STATUS_SAVE; + } else if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_LOAD) { + stub.pbdma_st.chsw_status = + NVGPU_PBDMA_CHSW_STATUS_LOAD; + } else if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_SWITCH) { + stub.pbdma_st.chsw_status = + NVGPU_PBDMA_CHSW_STATUS_SWITCH; + } else { + stub.pbdma_st.chsw_status = + NVGPU_PBDMA_CHSW_STATUS_INVALID; + } + stub.pbdma_st.id = + branches & F_PREEMPT_POLL_PBDMA_STATUS_ID_IS_TSGID ? + tsgid : tsgid + 1U; + stub.pbdma_st.next_id = branches & + F_PREEMPT_POLL_PBDMA_STATUS_NEXT_ID_IS_TSGID ? + tsgid : tsgid + 1U; + + err = gv11b_fifo_preempt_poll_pbdma(g, tsgid, 0U); + + if (branches & F_PREEMPT_POLL_PBDMA_TIMEOUT_INIT_FAIL) { + unit_assert(err == -ETIMEDOUT, goto done); + } else if ((branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_VALID) || + branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_SAVE) { + if (branches & + F_PREEMPT_POLL_PBDMA_STATUS_ID_IS_TSGID) { + unit_assert(err == -EBUSY, goto done); + } else { + unit_assert(err == 0, goto done); + } + } else if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_LOAD) { + if (branches & + F_PREEMPT_POLL_PBDMA_STATUS_NEXT_ID_IS_TSGID) { + unit_assert(err == -EBUSY, goto done); + } else { + unit_assert(err == 0, goto done); + } + } else if (branches & F_PREEMPT_POLL_PBDMA_CHSW_IS_SWITCH) { + if ((branches & + F_PREEMPT_POLL_PBDMA_STATUS_ID_IS_TSGID) || + (branches & + F_PREEMPT_POLL_PBDMA_STATUS_NEXT_ID_IS_TSGID)) { + unit_assert(err == -EBUSY, goto done); + } else { + unit_assert(err == 0, goto done); + } + } + nvgpu_posix_enable_fault_injection(timers_fi, false, 0); + } + + ret = UNIT_SUCCESS; + done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_preempt_poll_pbdma)); + } + + g->ops = gops; + return ret; +} + +static int stub_fifo_preempt_tsg(struct gk20a *g, struct nvgpu_tsg *tsg) +{ + return 1; +} + +#define F_PREEMPT_CHANNEL_TSGID_NULL BIT(0) +#define F_PREEMPT_CHANNEL_LAST BIT(1) + +static const char *f_preempt_channel[] = { + "channel_tsgid_null", +}; + +int test_gv11b_fifo_preempt_channel(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_FAIL; + int err = 0; + u32 branches = 0U; + struct nvgpu_channel ch; + struct gpu_ops gops = g->ops; + + ch.g = g; + g->ops.fifo.preempt_tsg = stub_fifo_preempt_tsg; + + for (branches = 0U; branches < F_PREEMPT_CHANNEL_LAST; branches++) { + unit_verbose(m, "%s branches=%s\n", + __func__, branches_str(branches, f_preempt_channel)); + + ch.tsgid = branches & F_PREEMPT_CHANNEL_TSGID_NULL ? + NVGPU_INVALID_TSG_ID : 0U; + + err = gv11b_fifo_preempt_channel(g, &ch); + + if (branches & F_PREEMPT_CHANNEL_TSGID_NULL) { + unit_assert(err == 0, goto done); + } else { + unit_assert(err == 1, goto done); + } + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_preempt_channel)); + } + g->ops = gops; + return ret; +} + +static void stub_fifo_preempt_trigger(struct gk20a *g, u32 id, + unsigned int id_type) +{ + +} + +static int stub_fifo_is_preempt_pending_ebusy(struct gk20a *g, u32 id, + unsigned int id_type) +{ + return -EBUSY; +} + +static int stub_fifo_is_preempt_pending_pass(struct gk20a *g, u32 id, + unsigned int id_type) +{ + return 0; +} + +#define F_PREEMPT_TSG_RUNLIST_ID_INVALID BIT(0) +#define F_PREEMPT_TSG_PREEMPT_LOCKED_FAIL BIT(1) +#define F_PREEMPT_TSG_PLATFORM_SILICON BIT(2) +#define F_PREEMPT_TSG_LAST BIT(3) + +static const char *f_preempt_tsg[] = { + "runlist_id_invalid", +}; + +int test_gv11b_fifo_preempt_tsg(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_FAIL; + int err = 0; + u32 branches = 0U; + u32 prune = F_PREEMPT_TSG_RUNLIST_ID_INVALID; + struct nvgpu_channel *ch = NULL; + struct nvgpu_tsg *tsg = NULL; + struct gpu_ops gops = g->ops; + struct nvgpu_os_posix *p = nvgpu_os_posix_from_gk20a(g); + + err = nvgpu_runlist_setup_sw(g); + unit_assert(err == 0, goto done); + + tsg = nvgpu_tsg_open(g, getpid()); + unit_assert(tsg != NULL, goto done); + + ch = nvgpu_channel_open_new(g, NVGPU_INVALID_RUNLIST_ID, false, + getpid(), getpid()); + unit_assert(ch != NULL, goto done); + + err = nvgpu_tsg_bind_channel(tsg, ch); + unit_assert(err == 0, goto done); + + g->ops.fifo.preempt_trigger = stub_fifo_preempt_trigger; + + for (branches = 0U; branches < F_PREEMPT_TSG_LAST; branches++) { + if (pruned(branches, prune)) { + unit_verbose(m, "%s branches=%s (pruned)\n", __func__, + branches_str(branches, f_preempt_tsg)); + continue; + } + unit_verbose(m, "%s branches=%s\n", + __func__, branches_str(branches, f_preempt_tsg)); + + tsg->runlist_id = branches & F_PREEMPT_TSG_RUNLIST_ID_INVALID ? + NVGPU_INVALID_RUNLIST_ID : 0U; + + g->ops.fifo.is_preempt_pending = + branches & F_PREEMPT_TSG_PREEMPT_LOCKED_FAIL ? + stub_fifo_is_preempt_pending_ebusy : + stub_fifo_is_preempt_pending_pass; + + p->is_silicon = + branches & F_PREEMPT_TSG_PLATFORM_SILICON ? + true : false; + + err = EXPECT_BUG(gv11b_fifo_preempt_tsg(g, tsg)); + + if (branches & F_PREEMPT_TSG_PREEMPT_LOCKED_FAIL) { + if (branches & F_PREEMPT_TSG_PLATFORM_SILICON) { + unit_assert(err == 0, goto done); + } else { + unit_assert(err == 1, goto done); + } + } else { + unit_assert(err == 0, goto done); + } + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_preempt_tsg)); + } + g->ops.fifo.is_preempt_pending = + stub_fifo_is_preempt_pending_pass; + err = nvgpu_tsg_unbind_channel(tsg, ch); + if (err != 0) { + unit_err(m, "Cannot unbind channel\n"); + } + if (ch != NULL) { + nvgpu_channel_close(ch); + } + if (tsg != NULL) { + nvgpu_ref_put(&tsg->refcount, nvgpu_tsg_release); + } + g->ops = gops; + p->is_silicon = false; + return ret; +} + +static bool stub_mc_is_stall_and_eng_intr_pending_true(struct gk20a *g, + u32 act_eng_id, u32 *eng_intr_pending) +{ + *eng_intr_pending = stub.eng_intr_pending; + return true; +} + +static bool stub_mc_is_stall_and_eng_intr_pending_false(struct gk20a *g, + u32 act_eng_id, u32 *eng_intr_pending) +{ + *eng_intr_pending = stub.eng_intr_pending; + return false; +} + +#define F_PREEMPT_PENDING_ID_TYPE_TSG BIT(0) +#define F_PREEMPT_PENDING_POLL_PBDMA_FAIL BIT(1) +#define F_PREEMPT_PENDING_PLATFORM_SILICON BIT(2) +#define F_PREEMPT_PENDING_POLL_ENG_TIMEOUT_FAIL BIT(3) +#define F_PREEMPT_PENDING_POLL_ENG_INTR_PENDING BIT(4) +#define F_PREEMPT_PENDING_CTX_STAT_VALID BIT(5) +#define F_PREEMPT_PENDING_CTX_STAT_SAVE BIT(6) +#define F_PREEMPT_PENDING_CTX_STAT_LOAD BIT(7) +#define F_PREEMPT_PENDING_CTX_STAT_SWITCH BIT(8) +#define F_PREEMPT_PENDING_ENG_STATUS_ID_IS_EQUAL BIT(9) +#define F_PREEMPT_PENDING_ENG_STATUS_NEXT_ID_IS_EQUAL BIT(10) +#define F_PREEMPT_PENDING_ENG_INTR_PENDING0 BIT(11) +#define F_PREEMPT_PENDING_POLL_ENG_PRE_SI_RETRIES BIT(12) +#define F_PREEMPT_PENDING_LAST BIT(13) + +static const char *f_preempt_pending[] = { + "id_type_tsg", + "poll_pbdma_fail", + "platform_silicon", + "poll_eng_timeout_init_fail", + "eng_intr_pending_true", + "ctx_stat_valid", + "ctx_stat_save", + "ctx_stat_load", + "ctx_stat_switch", + "eng_status_id_is_equal_given_id", + "eng_status_next_id_is_equal_given_id", + "eng_intr_pending_is_0", +}; + +int test_gv11b_fifo_is_preempt_pending(struct unit_module *m, struct gk20a *g, + void *args) +{ + int ret = UNIT_FAIL; + int err = 0; + u32 branches = 0U; + u32 prune = F_PREEMPT_PENDING_POLL_ENG_PRE_SI_RETRIES; + struct nvgpu_channel *ch = NULL; + struct nvgpu_tsg *tsg = NULL; + struct gpu_ops gops = g->ops; + unsigned int id_type; + struct nvgpu_posix_fault_inj *timers_fi; + struct nvgpu_os_posix *p = nvgpu_os_posix_from_gk20a(g); + u32 ctx_stat = 0U; + u32 id = 0U, next_id = 0U; + /* Assuming runlist_id is 0 */ + u32 runlist_served_pbdmas = g->fifo.runlist_info[0U]->pbdma_bitmask; + + timers_fi = nvgpu_timers_get_fault_injection(); + + err = nvgpu_runlist_setup_sw(g); + unit_assert(err == 0, goto done); + + tsg = nvgpu_tsg_open(g, getpid()); + unit_assert(tsg != NULL, goto done); + + ch = nvgpu_channel_open_new(g, NVGPU_INVALID_RUNLIST_ID, false, + getpid(), getpid()); + unit_assert(ch != NULL, goto done); + + err = nvgpu_tsg_bind_channel(tsg, ch); + unit_assert(err == 0, goto done); + + g->ops.pbdma.handle_intr = stub_pbdma_handle_intr; + + for (branches = 0U; branches < F_PREEMPT_PENDING_LAST; branches++) { + if (pruned(branches, prune)) { + unit_verbose(m, "%s branches=%s (pruned)\n", __func__, + branches_str(branches, f_preempt_pending)); + continue; + } + unit_verbose(m, "%s branches=%s\n", + __func__, branches_str(branches, f_preempt_pending)); + + id_type = branches & F_PREEMPT_PENDING_ID_TYPE_TSG ? + ID_TYPE_TSG : ID_TYPE_UNKNOWN; + + p->is_silicon = + branches & F_PREEMPT_PENDING_PLATFORM_SILICON ? + true : false; + + if (branches & F_PREEMPT_PENDING_POLL_PBDMA_FAIL) { + nvgpu_posix_enable_fault_injection(timers_fi, true, 0U); + } else if (branches & F_PREEMPT_PENDING_POLL_ENG_TIMEOUT_FAIL) { + nvgpu_posix_enable_fault_injection(timers_fi, true, + __builtin_popcount(runlist_served_pbdmas)); + } + + /* + * Note: Force pbdma_status invalid to skip poll pbdma + * which is tested separately. + */ + stub.pbdma_st.chsw_status = NVGPU_PBDMA_CHSW_STATUS_INVALID; + + if (branches & F_PREEMPT_PENDING_POLL_ENG_PRE_SI_RETRIES) { + /* Timeout should not expire */ + nvgpu_posix_enable_fault_injection(timers_fi, true, + PREEMPT_PENDING_POLL_PRE_SI_RETRIES + 4U); + + /* Force engine status = ctxsw_switch */ + branches |= F_PREEMPT_PENDING_CTX_STAT_SWITCH; + /* Force eng_intr_pending = 0 */ + branches |= F_PREEMPT_PENDING_ENG_INTR_PENDING0; + } + + g->ops.mc.is_stall_and_eng_intr_pending = + branches & F_PREEMPT_PENDING_POLL_ENG_INTR_PENDING ? + stub_mc_is_stall_and_eng_intr_pending_true : + stub_mc_is_stall_and_eng_intr_pending_false; + + if (branches & F_PREEMPT_PENDING_CTX_STAT_SWITCH) { + ctx_stat = + fifo_engine_status_ctx_status_ctxsw_switch_v(); + } else if (branches & F_PREEMPT_PENDING_CTX_STAT_VALID) { + ctx_stat = fifo_engine_status_ctx_status_valid_v(); + } else if (branches & F_PREEMPT_PENDING_CTX_STAT_SAVE) { + ctx_stat = fifo_engine_status_ctx_status_ctxsw_save_v(); + } else if (branches & F_PREEMPT_PENDING_CTX_STAT_LOAD) { + ctx_stat = fifo_engine_status_ctx_status_ctxsw_load_v(); + } else { + ctx_stat = 0U; + } + + id = branches & F_PREEMPT_PENDING_ENG_STATUS_ID_IS_EQUAL ? + 0U : 1U; + + next_id = branches & + F_PREEMPT_PENDING_ENG_STATUS_NEXT_ID_IS_EQUAL ? + 0U : 1U; + + stub.eng_stat = ((ctx_stat & 0x7U) << 13) | (id & 0xfffU) | + ((next_id & 0xfffU) << 16); + + stub.eng_intr_pending = + branches & F_PREEMPT_PENDING_ENG_INTR_PENDING0 ? + 0U : 1U; + + /* Modify eng_stat for engine 0 */ + nvgpu_writel(g, fifo_engine_status_r(0U), stub.eng_stat); + + err = gv11b_fifo_is_preempt_pending(g, 0U, id_type); + + if (branches & F_PREEMPT_PENDING_POLL_PBDMA_FAIL) { + unit_assert(err == -ETIMEDOUT, goto done); + } else if (branches & F_PREEMPT_PENDING_POLL_ENG_TIMEOUT_FAIL) { + unit_assert(err == -ETIMEDOUT, goto done); + } else if ((branches & F_PREEMPT_PENDING_CTX_STAT_SWITCH) && + (branches & F_PREEMPT_PENDING_ENG_INTR_PENDING0)) { + unit_assert(err == -EBUSY, goto done); + } else if ((branches & F_PREEMPT_PENDING_CTX_STAT_VALID) || + (branches & F_PREEMPT_PENDING_CTX_STAT_SAVE)) { + if ((branches & + F_PREEMPT_PENDING_ENG_STATUS_ID_IS_EQUAL) && + (branches & + F_PREEMPT_PENDING_ENG_INTR_PENDING0)) { + unit_assert(err == -EBUSY, goto done); + } else { + unit_assert(err == 0, goto done); + } + } else if (branches & F_PREEMPT_PENDING_CTX_STAT_LOAD) { + if ((branches & + F_PREEMPT_PENDING_ENG_STATUS_NEXT_ID_IS_EQUAL) && + (branches & F_PREEMPT_PENDING_ENG_INTR_PENDING0)) { + unit_assert(err == -EBUSY, goto done); + } else { + unit_assert(err == 0, goto done); + } + } else { + unit_assert(err == 0, goto done); + } + + nvgpu_posix_enable_fault_injection(timers_fi, false, 0); + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_preempt_pending)); + } + g->ops.fifo.is_preempt_pending = + stub_fifo_is_preempt_pending_pass; + err = nvgpu_tsg_unbind_channel(tsg, ch); + if (err != 0) { + unit_err(m, "Cannot unbind channel\n"); + } + if (ch != NULL) { + nvgpu_channel_close(ch); + } + if (tsg != NULL) { + nvgpu_ref_put(&tsg->refcount, nvgpu_tsg_release); + } + nvgpu_runlist_cleanup_sw(g); + g->ops = gops; + p->is_silicon = false; + return ret; +} + +struct unit_module_test nvgpu_preempt_gv11b_tests[] = { + UNIT_TEST(init_support, test_fifo_init_support, &unit_ctx, 0), + UNIT_TEST(preempt_trigger, test_gv11b_fifo_preempt_trigger, NULL, 0), + UNIT_TEST(preempt_runlists_for_rc, test_gv11b_fifo_preempt_runlists_for_rc, NULL, 0), + UNIT_TEST(preempt_poll_pbdma, test_gv11b_fifo_preempt_poll_pbdma, NULL, 0), + UNIT_TEST(preempt_channel, test_gv11b_fifo_preempt_channel, NULL, 0), + UNIT_TEST(preempt_tsg, test_gv11b_fifo_preempt_tsg, NULL, 0), + UNIT_TEST(is_preempt_pending, test_gv11b_fifo_is_preempt_pending, NULL, 0), + UNIT_TEST(remove_support, test_fifo_remove_support, &unit_ctx, 0), +}; + +UNIT_MODULE(nvgpu_preempt_gv11b, nvgpu_preempt_gv11b_tests, UNIT_PRIO_NVGPU_TEST); diff --git a/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.h b/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.h new file mode 100644 index 000000000..8c610d1e3 --- /dev/null +++ b/userspace/units/fifo/preempt/gv11b/nvgpu-preempt-gv11b.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2020, 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_PREEMPT_GV11B_H +#define UNIT_NVGPU_PREEMPT_GV11B_H + +#include + +struct unit_module; +struct gk20a; + +/** @addtogroup SWUTS-fifo-preempt-gv11b + * @{ + * + * Software Unit Test Specification for fifo/preempt/gv11b + */ + +/** + * Test specification for: test_gv11b_fifo_preempt_trigger + * + * Description: Test fifo preempt trigger + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_preempt_trigger + * + * Input: test_fifo_init_support + * + * Steps: + * - Preempt trigger writes given id to the preempt register if id type is TSG. + * - Read preempt register to check if preempt register value is equal to given + * id for TSG type id or original value otherwise. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_preempt_trigger(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_gv11b_fifo_preempt_runlists_for_rc + * + * Description: Test runlist preempt + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_preempt_runlists_for_rc, gv11b_fifo_issue_runlist_preempt + * + * Input: test_fifo_init_support + * + * Steps: + * - Bits corresponding to active runlists are set to issue runlist preempt. + * - Check that value stored in memory is as expected. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_preempt_runlists_for_rc(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gv11b_fifo_preempt_poll_pbdma + * + * Description: Test preempt pbdma with tsg/ch poll + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_preempt_poll_pbdma, fifo_preempt_check_tsg_on_pbdma + * + * Input: test_fifo_init_support + * + * Steps: + * - Introduce different cases of ch/tsg status on PBDMA. + * - Check that pbdma preempt returns success for valid cases. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_preempt_poll_pbdma(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_gv11b_fifo_preempt_channel + * + * Description: Test channel preempt + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_preempt_channel + * + * Input: test_fifo_init_support + * + * Steps: + * - Check that preemption of channel with valid tsgid triggers tsg preempt. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_preempt_channel(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_gv11b_fifo_preempt_tsg + * + * Description: Test TSG preempt + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_preempt_tsg, gv11b_fifo_preempt_locked + * + * Input: test_fifo_init_support + * + * Steps: + * - Write h/w register to trigger TSG preempt. + * - Check if written value is as expected. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_preempt_tsg(struct unit_module *m, struct gk20a *g, + void *args); + +/** + * Test specification for: test_gv11b_fifo_is_preempt_pending + * + * Description: Test if preempt is pending + * + * Test Type: Feature based + * + * Targets: gv11b_fifo_is_preempt_pending, gv11b_fifo_preempt_poll_eng, + * fifo_check_eng_intr_pending + * + * Input: test_fifo_init_support + * + * Steps: + * - Check pbdma and engine preempt status; determine if preempt is completed. + * - Vary engine preempt status for various ctx status scenarios. + * - Check that the return value corresponds to input cases. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gv11b_fifo_is_preempt_pending(struct unit_module *m, struct gk20a *g, + void *args); +/** + * @} + */ + +#endif /* UNIT_NVGPU_PREEMPT_GV11B_H */