From eea6feec2323145d1869cb3df71030fa6bc40e99 Mon Sep 17 00:00:00 2001 From: Philip Elcan Date: Mon, 5 Nov 2018 10:45:40 -0500 Subject: [PATCH] gpu: nvgpu: unit: add gm20b to fuse test This adds unit testing for gm20b to the fuse unit test. This provides 100% code and branch coverage for this module/device. JIRA NVGPU-938 Change-Id: I766098bfe96044be18d0dbf74b277d1079d263f0 Signed-off-by: Philip Elcan Reviewed-on: https://git-master.nvidia.com/r/1943386 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/libnvgpu-drv.export | 1 + userspace/units/fuse/Makefile | 3 +- userspace/units/fuse/Makefile.tmk | 3 +- userspace/units/fuse/nvgpu-fuse-gm20b.c | 333 ++++++++++++++++++++++++ userspace/units/fuse/nvgpu-fuse-gm20b.h | 45 ++++ userspace/units/fuse/nvgpu-fuse.c | 18 ++ 6 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 userspace/units/fuse/nvgpu-fuse-gm20b.c create mode 100644 userspace/units/fuse/nvgpu-fuse-gm20b.h diff --git a/drivers/gpu/nvgpu/libnvgpu-drv.export b/drivers/gpu/nvgpu/libnvgpu-drv.export index f79a8f028..4235b3a3f 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv.export @@ -19,6 +19,7 @@ find_next_bit gk20a_bus_set_bar0_window gk20a_get_ch_runlist_entry gk20a_get_tsg_runlist_entry +gm20b_fuse_status_opt_gpc nvgpu_alloc nvgpu_alloc_base nvgpu_alloc_common_init diff --git a/userspace/units/fuse/Makefile b/userspace/units/fuse/Makefile index 041f1c217..5303618b7 100644 --- a/userspace/units/fuse/Makefile +++ b/userspace/units/fuse/Makefile @@ -21,7 +21,8 @@ .SUFFIXES: OBJS = nvgpu-fuse.o \ - nvgpu-fuse-gp10b.o + nvgpu-fuse-gp10b.o \ + nvgpu-fuse-gm20b.o MODULE = nvgpu-fuse include ../Makefile.units diff --git a/userspace/units/fuse/Makefile.tmk b/userspace/units/fuse/Makefile.tmk index 593c32653..7054ccbf2 100644 --- a/userspace/units/fuse/Makefile.tmk +++ b/userspace/units/fuse/Makefile.tmk @@ -14,7 +14,8 @@ NVGPU_UNIT_NAME=nvgpu-fuse NVGPU_UNIT_SRCS=nvgpu-fuse.c \ - nvgpu-fuse-gp10b.c + nvgpu-fuse-gp10b.c \ + nvgpu-fuse-gm20b.c include $(NV_COMPONENT_DIR)/../Makefile.units.common.tmk diff --git a/userspace/units/fuse/nvgpu-fuse-gm20b.c b/userspace/units/fuse/nvgpu-fuse-gm20b.c new file mode 100644 index 000000000..cea6e0314 --- /dev/null +++ b/userspace/units/fuse/nvgpu-fuse-gm20b.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2018, 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 "common/fuse/fuse_gm20b.h" + +#include "nvgpu-fuse-priv.h" +#include "nvgpu-fuse-gm20b.h" + +/* register definitions for this block */ +#define GM20B_FUSE_REG_BASE 0x00021000U +#define GM20B_FUSE_OPT_SEC_DEBUG_EN (GM20B_FUSE_REG_BASE+0x218U) +#define GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN (GM20B_FUSE_REG_BASE+0x434U) +#define GM20B_FUSE_CTRL_OPT_TPC_GPC (GM20B_FUSE_REG_BASE+0x838U) +#define GM20B_FUSE_STATUS_OPT_FBIO (GM20B_FUSE_REG_BASE+0xC14U) +#define GM20B_FUSE_STATUS_OPT_GPC (GM20B_FUSE_REG_BASE+0xC1CU) +#define GM20B_FUSE_STATUS_OPT_TPC_GPC (GM20B_FUSE_REG_BASE+0xC38U) +#define GM20B_FUSE_STATUS_OPT_FBP (GM20B_FUSE_REG_BASE+0xD38U) +#define GM20B_FUSE_STATUS_OPT_ROP_L2_FBP (GM20B_FUSE_REG_BASE+0xD70U) +#define GM20B_MAX_FBPS_COUNT 32U +#define GM20B_MAX_GPC_COUNT 32U + +/* for common init args */ +struct fuse_test_args gm20b_init_args = { + .gpu_arch = 0x12, + .gpu_impl = 0xb, + .fuse_base_addr = GM20B_FUSE_REG_BASE, + .sec_fuse_addr = GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN, +}; + +/* + * Verify fuse API check_priv_security() when security fuse is enabled. + * Tests with secure debug enabled and disabled. + */ +int test_fuse_gm20b_check_sec(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + int result; + u32 i; + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN, + 0x1); + + gcplex_config = GCPLEX_CONFIG_WPR_ENABLED_MASK & + ~GCPLEX_CONFIG_VPR_AUTO_FETCH_DISABLE_MASK; + + for (i = 0; i < 2; i++) { + /* ACR enable/disable */ + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_OPT_SEC_DEBUG_EN, + i); + result = g->ops.fuse.check_priv_security(g); + if (result != 0) { + unit_err(m, "%s: fuse_check_priv_security returned " + "error %d\n", __func__, result); + ret = UNIT_FAIL; + } + + if (!nvgpu_is_enabled(g, NVGPU_SEC_PRIVSECURITY)) { + unit_err(m, "%s: NVGPU_SEC_PRIVSECURITY disabled\n", + __func__); + ret = UNIT_FAIL; + } + + if (nvgpu_is_enabled(g, NVGPU_SEC_SECUREGPCCS)) { + unit_err(m, "%s: NVGPU_SEC_SECUREGPCCS enabled\n", + __func__); + ret = UNIT_FAIL; + } + } + + return ret; +} + +/* + * Verify fuse API check_priv_security() handles an error from reading gcplex + */ +int test_fuse_gm20b_check_gcplex_fail(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + int result; + + g->ops.fuse.read_gcplex_config_fuse = read_gcplex_config_fuse_fail; + result = g->ops.fuse.check_priv_security(g); + if (result == 0) { + unit_err(m, "%s: fuse_check_priv_security should have returned " + " error\n", __func__); + ret = UNIT_FAIL; + } + + g->ops.fuse.read_gcplex_config_fuse = read_gcplex_config_fuse_pass; + + return ret; +} + +/* + * Verify fuse API check_priv_security() handles invalid gcplex configurations + * of WPR and VPR bits. + */ +int test_fuse_gm20b_check_sec_invalid_gcplex(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + int result; + u32 gcplex_values[] = { + 0, + ~GCPLEX_CONFIG_WPR_ENABLED_MASK & + GCPLEX_CONFIG_VPR_AUTO_FETCH_DISABLE_MASK, + GCPLEX_CONFIG_WPR_ENABLED_MASK | + GCPLEX_CONFIG_VPR_AUTO_FETCH_DISABLE_MASK, + }; + int gcplex_entries = sizeof(gcplex_values)/sizeof(gcplex_values[0]); + int i; + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN, + 0x1); + + for (i = 0; i < gcplex_entries; i++) { + gcplex_config = gcplex_values[i]; + result = g->ops.fuse.check_priv_security(g); + if (result == 0) { + unit_err(m, "%s: fuse_check_priv_security should have returned " + "error, i = %d, gcplex_config = %x\n", + __func__, i, gcplex_config); + ret = UNIT_FAIL; + } + } + + return ret; +} + + +/* + * Verify fuse API check_priv_security() when security fuse is enabled. + */ +int test_fuse_gm20b_check_non_sec(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + int result; + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN, + 0x0); + + result = g->ops.fuse.check_priv_security(g); + if (result != 0) { + unit_err(m, "%s: fuse_check_priv_security returned " + "error %d\n", __func__, result); + ret = UNIT_FAIL; + } + + if (nvgpu_is_enabled(g, NVGPU_SEC_PRIVSECURITY)) { + unit_err(m, "%s: NVGPU_SEC_PRIVSECURITY enabled\n", __func__); + ret = UNIT_FAIL; + } + + if (nvgpu_is_enabled(g, NVGPU_SEC_SECUREGPCCS)) { + unit_err(m, "%s: NVGPU_SEC_SECUREGPCCS enabled\n", __func__); + ret = UNIT_FAIL; + } + + return ret; +} + +/* Verify fuse reads for basic value return APIs */ +int test_fuse_gm20b_basic_fuses(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + u32 set, val, i; + + for (set = 0; set <= 1; set++) { + unit_info(m, "set for basic fuses = %u\n", set); + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_FBIO, + set); + val = g->ops.fuse.fuse_status_opt_fbio(g); + if (val != set) { + unit_err(m, "%s: FBIO fuse incorrect %u != %u\n", + __func__, val, set); + ret = UNIT_FAIL; + } + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_FBP, + set); + val = g->ops.fuse.fuse_status_opt_fbp(g); + if (val != set) { + unit_err(m, "%s: FBP fuse incorrect %u != %u\n", + __func__, val, set); + ret = UNIT_FAIL; + } + + for (i = 0; i < GM20B_MAX_FBPS_COUNT; i++) { + nvgpu_posix_io_writel_reg_space(g, + GM20B_FUSE_STATUS_OPT_ROP_L2_FBP+(i*4U), + set+i); + } + for (i = 0; i < GM20B_MAX_FBPS_COUNT; i++) { + val = g->ops.fuse.fuse_status_opt_rop_l2_fbp(g, i); + if (val != (set+i)) { + unit_err(m, + "%s: ROP_L2_FBP incorrect %u != %u\n", + __func__, val, set+i); + ret = UNIT_FAIL; + break; + } + } + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_STATUS_OPT_GPC, + set); + /* + * the fuse_status_opt_gpc() function pointer isn't set + * for gm20b + */ + val = gm20b_fuse_status_opt_gpc(g); + if (val != set) { + unit_err(m, "%s: GPC fuse incorrect %u != %u\n", + __func__, val, set); + ret = UNIT_FAIL; + } + + for (i = 0; i < GM20B_MAX_GPC_COUNT; i++) { + g->ops.fuse.fuse_ctrl_opt_tpc_gpc(g, i, set*i); + } + for (i = 0; i < GM20B_MAX_GPC_COUNT; i++) { + val = nvgpu_posix_io_readl_reg_space(g, + GM20B_FUSE_CTRL_OPT_TPC_GPC+(i*4U)); + if (val != (set*i)) { + unit_err(m, + "%s TPC CTRL incorrect %u != %u\n", + __func__, val, set*i); + ret = UNIT_FAIL; + break; + } + } + + for (i = 0; i < GM20B_MAX_GPC_COUNT; i++) { + nvgpu_posix_io_writel_reg_space(g, + GM20B_FUSE_STATUS_OPT_TPC_GPC+(i*4U), + set*i); + + } + for (i = 0; i < GM20B_MAX_GPC_COUNT; i++) { + val = g->ops.fuse.fuse_status_opt_tpc_gpc(g, i); + if (val != (set*i)) { + unit_err(m, + "%s TPC STATUS incorrect %u != %u\n", + __func__, val, set*i); + ret = UNIT_FAIL; + break; + } + } + + nvgpu_posix_io_writel_reg_space(g, GM20B_FUSE_OPT_SEC_DEBUG_EN, + set); + val = g->ops.fuse.fuse_opt_sec_debug_en(g); + if (val != set) { + unit_err(m, + "%s: SEC_DEBUG_EN fuse incorrect %u != %u\n", + __func__, val, set); + ret = UNIT_FAIL; + } + + nvgpu_posix_io_writel_reg_space(g, + GM20B_FUSE_STATUS_OPT_PRIV_SEC_EN, + set); + val = g->ops.fuse.fuse_opt_priv_sec_en(g); + if (val != set) { + unit_err(m, + "%s: PRIV_SEC_EN fuse incorrect %u != %u\n", + __func__, val, set); + ret = UNIT_FAIL; + } + } + + return ret; +} + +/* Verify when FMODEL is enabled, fuse module reports non-secure */ +int test_fuse_gm20b_check_fmodel(struct unit_module *m, + struct gk20a *g, void *__args) +{ + int ret = UNIT_SUCCESS; + int result; + + __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, true); + + result = g->ops.fuse.check_priv_security(g); + if (result != 0) { + unit_err(m, "%s: fuse_check_priv_security returned " + "error %d\n", __func__, result); + ret = UNIT_FAIL; + } + + if (!nvgpu_is_enabled(g, NVGPU_SEC_PRIVSECURITY)) { + unit_err(m, "%s: NVGPU_SEC_PRIVSECURITY disabled\n", __func__); + ret = UNIT_FAIL; + } + + if (nvgpu_is_enabled(g, NVGPU_SEC_SECUREGPCCS)) { + unit_err(m, "%s: NVGPU_SEC_SECUREGPCCS enabled\n", __func__); + ret = UNIT_FAIL; + } + + __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, false); + return ret; +} diff --git a/userspace/units/fuse/nvgpu-fuse-gm20b.h b/userspace/units/fuse/nvgpu-fuse-gm20b.h new file mode 100644 index 000000000..1bc888108 --- /dev/null +++ b/userspace/units/fuse/nvgpu-fuse-gm20b.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018, 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_FUSE_GM20B_H__ +#define __UNIT_NVGPU_FUSE_GM20B_H__ + +extern struct fuse_test_args gm20b_init_args; + +int test_fuse_gm20b_check_sec(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_check_gcplex_fail(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_check_sec_invalid_gcplex(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_ecc(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_feature_override_disable(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_check_non_sec(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_basic_fuses(struct unit_module *m, + struct gk20a *g, void *__args); +int test_fuse_gm20b_check_fmodel(struct unit_module *m, + struct gk20a *g, void *__args); + +#endif /* __UNIT_NVGPU_FUSE_GM20B_H__ */ diff --git a/userspace/units/fuse/nvgpu-fuse.c b/userspace/units/fuse/nvgpu-fuse.c index 0f3cc11b3..de0579369 100644 --- a/userspace/units/fuse/nvgpu-fuse.c +++ b/userspace/units/fuse/nvgpu-fuse.c @@ -30,6 +30,7 @@ #include "nvgpu-fuse-priv.h" #include "nvgpu-fuse-gp10b.h" +#include "nvgpu-fuse-gm20b.h" /* * Mock I/O @@ -154,6 +155,23 @@ struct unit_module_test fuse_tests[] = { UNIT_TEST(fuse_gp10b_check_fmodel, test_fuse_gp10b_check_fmodel, NULL), UNIT_TEST(fuse_gp10b_cleanup, test_fuse_device_common_cleanup, &gp10b_init_args), + + UNIT_TEST(fuse_gm20b_init, test_fuse_device_common_init, + &gm20b_init_args), + UNIT_TEST(fuse_gm20b_check_sec, test_fuse_gm20b_check_sec, NULL), + UNIT_TEST(fuse_gm20b_check_sec_invalid_gcplex, + test_fuse_gm20b_check_sec_invalid_gcplex, + NULL), + UNIT_TEST(fuse_gm20b_check_gcplex_fail, + test_fuse_gm20b_check_gcplex_fail, + NULL), + UNIT_TEST(fuse_gm20b_check_non_sec, + test_fuse_gm20b_check_non_sec, + NULL), + UNIT_TEST(fuse_gm20b_basic_fuses, test_fuse_gm20b_basic_fuses, NULL), + UNIT_TEST(fuse_gm20b_check_fmodel, test_fuse_gm20b_check_fmodel, NULL), + UNIT_TEST(fuse_gm20b_cleanup, test_fuse_device_common_cleanup, + &gm20b_init_args), }; UNIT_MODULE(fuse, fuse_tests, UNIT_PRIO_NVGPU_TEST);