From b8c25a5a555f9bdd7d0245bf642bd4eb87f5dfea Mon Sep 17 00:00:00 2001 From: Philip Elcan Date: Mon, 11 Nov 2019 14:32:12 -0500 Subject: [PATCH] gpu: nvgpu: unit: init: add quiesce testing Add testing of quiesce functionality to init unit test. JIRA NVGPU-3981 Change-Id: Idc64179bc8d532bea385e705d96fb4b376d15cd9 Signed-off-by: Philip Elcan Reviewed-on: https://git-master.nvidia.com/r/2247154 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/init/nvgpu_init.c | 1 + drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 2 + drivers/gpu/nvgpu/os/posix/nvgpu.c | 2 + userspace/required_tests.json | 6 ++ userspace/units/init/nvgpu-init.c | 117 +++++++++++++++++++++ userspace/units/init/nvgpu-init.h | 21 ++++ 6 files changed, 149 insertions(+) diff --git a/drivers/gpu/nvgpu/common/init/nvgpu_init.c b/drivers/gpu/nvgpu/common/init/nvgpu_init.c index 4e83b2f17..1c6a924a5 100644 --- a/drivers/gpu/nvgpu/common/init/nvgpu_init.c +++ b/drivers/gpu/nvgpu/common/init/nvgpu_init.c @@ -171,6 +171,7 @@ void nvgpu_sw_quiesce(struct gk20a *g) g->sw_quiesce_pending = true; nvgpu_cond_signal(&g->sw_quiesce_cond); + return; fail: diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index c557dac3a..658045def 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -465,7 +465,9 @@ nvgpu_sw_quiesce nvgpu_sw_quiesce_remove_support nvgpu_thread_create nvgpu_thread_create_priority +nvgpu_thread_get_fault_injection nvgpu_thread_is_running +nvgpu_thread_join nvgpu_thread_should_stop nvgpu_thread_stop nvgpu_thread_stop_graceful diff --git a/drivers/gpu/nvgpu/os/posix/nvgpu.c b/drivers/gpu/nvgpu/os/posix/nvgpu.c index 9546839bb..d5a4f8ade 100644 --- a/drivers/gpu/nvgpu/os/posix/nvgpu.c +++ b/drivers/gpu/nvgpu/os/posix/nvgpu.c @@ -66,11 +66,13 @@ void nvgpu_start_gpu_idle(struct gk20a *g) int nvgpu_enable_irqs(struct gk20a *g) { + g->mc.irqs_enabled = true; return 0; } void nvgpu_disable_irqs(struct gk20a *g) { + g->mc.irqs_enabled = false; } void nvgpu_set_power_state(struct gk20a *g, u32 state) diff --git a/userspace/required_tests.json b/userspace/required_tests.json index 5286a2182..49c3c0f14 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -767,6 +767,12 @@ "unit": "init", "test_level": 0 }, + { + "test": "test_quiesce", + "case": "init_quiesce", + "unit": "init", + "test_level": 0 + }, { "test": "test_setup_env", "case": "init_setup_env", diff --git a/userspace/units/init/nvgpu-init.c b/userspace/units/init/nvgpu-init.c index aa1e984e5..e25759fec 100644 --- a/userspace/units/init/nvgpu-init.c +++ b/userspace/units/init/nvgpu-init.c @@ -689,6 +689,122 @@ int test_poweroff(struct unit_module *m, struct gk20a *g, void *args) return UNIT_SUCCESS; } +static bool intr_masked; +static void mock_intr_mask(struct gk20a *g) +{ + intr_masked = true; +} + +static void mock_runlist_write_state(struct gk20a *g, u32 runlist_mask, + u32 runlist_state) +{ +} + +static void mock_fifo_preempt_runlists_for_rc(struct gk20a *g, u32 runlist_mask) +{ +} + +int test_quiesce(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret = UNIT_SUCCESS; + struct nvgpu_posix_fault_inj *thread_fi = + nvgpu_thread_get_fault_injection(); + int err; + unsigned long *save_enabled_ptr; + + /* assume quiesce has been initalized already */ + + /* make sure we're powered on */ + nvgpu_set_power_state(g, NVGPU_STATE_POWERED_ON); + + /* make sure we simulate interrupts enabled */ + g->mc.irqs_enabled = true; + intr_masked = false; + + /* setup HAL for masking interrupts */ + g->ops.mc.intr_mask = mock_intr_mask; + + /* + * quiesce will request fifo to quiesce, so make sure we don't have + * anything to do. + */ + g->fifo.num_runlists = 0; + g->fifo.num_channels = 0; + + /* mock out fifo HALs called during quiesce */ + g->ops.runlist.write_state = mock_runlist_write_state; + g->ops.fifo.preempt_runlists_for_rc = mock_fifo_preempt_runlists_for_rc; + + nvgpu_sw_quiesce(g); + /* wait for quiesce thread to complete */ + nvgpu_thread_join(&g->sw_quiesce_thread); + + + + if (g->mc.irqs_enabled || !intr_masked) { + unit_err(m, "quiesce failed to disable interrupts\n"); + ret = UNIT_FAIL; + } + + /* setup quiesce again */ + nvgpu_sw_quiesce_remove_support(g); + set_poweron_funcs_success(g); + err = nvgpu_finalize_poweron(g); + if (err != 0) { + unit_return_fail(m, "failed to re-enable quiesce\n"); + } + + /* coverage for thread_should_stop() being set using fault inj */ + nvgpu_posix_enable_fault_injection(thread_fi, true, 0); + nvgpu_sw_quiesce(g); + /* wait for quiesce thread to complete */ + nvgpu_thread_join(&g->sw_quiesce_thread); + nvgpu_posix_enable_fault_injection(thread_fi, false, 0); + + /* setup quiesce again */ + nvgpu_sw_quiesce_remove_support(g); + set_poweron_funcs_success(g); + err = nvgpu_finalize_poweron(g); + if (err != 0) { + unit_return_fail(m, "failed to re-enable quiesce\n"); + } + + /* branch coverage for error states when requesting quiesce */ + g->is_virtual = true; + nvgpu_sw_quiesce(g); + /* don't wait for quiesce thread to complete since this is error */ + g->is_virtual = false; + save_enabled_ptr = g->enabled_flags; + g->enabled_flags = NULL; + nvgpu_sw_quiesce(g); + /* don't wait for quiesce thread to complete since this is error */ + g->enabled_flags = save_enabled_ptr; + nvgpu_set_enabled(g, NVGPU_DISABLE_SW_QUIESCE, true); + nvgpu_sw_quiesce(g); + /* don't wait for quiesce thread to complete since this is error */ + nvgpu_set_enabled(g, NVGPU_DISABLE_SW_QUIESCE, false); + /* Note: quiesce should still be configured */ + + /* coverage for device powered off when quiesce requested */ + nvgpu_set_power_state(g, NVGPU_STATE_POWERED_OFF); + nvgpu_sw_quiesce(g); + /* wait for quiesce thread to complete */ + nvgpu_thread_join(&g->sw_quiesce_thread); + nvgpu_set_power_state(g, NVGPU_STATE_POWERED_ON); + + /* coverage for thread creation failing when creating thread */ + nvgpu_sw_quiesce_remove_support(g); + set_poweron_funcs_success(g); + nvgpu_posix_enable_fault_injection(thread_fi, true, 0); + err = nvgpu_finalize_poweron(g); + if (err == 0) { + unit_return_fail(m, "failed to detect thread creation error\n"); + } + nvgpu_posix_enable_fault_injection(thread_fi, false, 0); + + return ret; +} + struct unit_module_test init_tests[] = { UNIT_TEST(init_setup_env, test_setup_env, NULL, 0), UNIT_TEST(get_litter_value, test_get_litter_value, NULL, 0), @@ -699,6 +815,7 @@ struct unit_module_test init_tests[] = { UNIT_TEST(init_poweron, test_poweron, NULL, 0), UNIT_TEST(init_poweron_branches, test_poweron_branches, NULL, 0), UNIT_TEST(init_poweroff, test_poweroff, NULL, 0), + UNIT_TEST(init_quiesce, test_quiesce, NULL, 0), UNIT_TEST(init_free_env, test_free_env, NULL, 0), }; diff --git a/userspace/units/init/nvgpu-init.h b/userspace/units/init/nvgpu-init.h index 113c82403..6c3d520be 100644 --- a/userspace/units/init/nvgpu-init.h +++ b/userspace/units/init/nvgpu-init.h @@ -298,4 +298,25 @@ int test_poweron_branches(struct unit_module *m, struct gk20a *g, void *args); */ int test_poweroff(struct unit_module *m, struct gk20a *g, void *args); +/** + * Test specification for: test_quiesce + * + * Description: Test putting device in quiesce + * + * Test Type: Feature based + * + * Targets: nvgpu_sw_quiesce_init_support, nvgpu_sw_quiesce_remove_support, + * nvgpu_sw_quiesce_thread, nvgpu_sw_quiesce + * + * Input: + * - test_setup_env() must be called before. + * + * Steps: + * + * Output: + * - UNIT_FAIL if nvgpu_finalize_poweron() ever returns the unexpected value. + * - UNIT_SUCCESS otherwise + */ +int test_quiesce(struct unit_module *m, struct gk20a *g, void *args); + #endif /* UNIT_NVGPU_INIT_H */