diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index a15a5375c..1ba79902f 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -81,6 +81,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/fifo/engine/gv100 NV_REPOSITORY_COMPONENTS += userspace/units/fifo/engine/gv11b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma/gv11b +NV_REPOSITORY_COMPONENTS += userspace/units/fifo/pbdma/gm20b NV_REPOSITORY_COMPONENTS += userspace/units/fifo/runlist NV_REPOSITORY_COMPONENTS += userspace/units/fifo/runlist/gk20a NV_REPOSITORY_COMPONENTS += userspace/units/fifo/runlist/gv11b diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index b3b44fffe..d93d4f90a 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -33,6 +33,19 @@ gm20b_fb_tlb_invalidate gm20b_gr_falcon_get_fecs_ctx_state_store_major_rev_id gm20b_is_engine_gr gm20b_mm_get_big_page_sizes +gm20b_pbdma_acquire_val +gm20b_pbdma_device_fatal_0_intr_descs +gm20b_pbdma_format_gpfifo_entry +gm20b_pbdma_get_fc_subdevice +gm20b_pbdma_get_gp_base +gm20b_pbdma_get_gp_base_hi +gm20b_pbdma_get_userd_addr +gm20b_pbdma_get_userd_aperture_mask +gm20b_pbdma_get_userd_hi_addr +gm20b_pbdma_handle_intr +gm20b_pbdma_handle_intr_0 +gm20b_pbdma_read_data +gm20b_pbdma_restartable_0_intr_descs gm20b_ramin_set_big_page_size gm20b_read_engine_status_info gm20b_top_get_max_gpc_count diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index ef510e5d0..1e1818d5e 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -88,6 +88,7 @@ UNITS := \ $(UNIT_SRC)/fifo/engine/gv100 \ $(UNIT_SRC)/fifo/engine/gv11b \ $(UNIT_SRC)/fifo/pbdma \ + $(UNIT_SRC)/fifo/pbdma/gm20b \ $(UNIT_SRC)/fifo/pbdma/gv11b \ $(UNIT_SRC)/fifo/runlist \ $(UNIT_SRC)/fifo/runlist/gk20a \ diff --git a/userspace/SWUTS.h b/userspace/SWUTS.h index b10b12f2f..966b8bce1 100644 --- a/userspace/SWUTS.h +++ b/userspace/SWUTS.h @@ -47,6 +47,7 @@ * - @ref SWUTS-fifo-engine-gv100 * - @ref SWUTS-fifo-engine-gv11b * - @ref SWUTS-fifo-pbdma + * - @ref SWUTS-fifo-pbdma-gm20b * - @ref SWUTS-fifo-pbdma-gv11b * - @ref SWUTS-fifo-runlist * - @ref SWUTS-fifo-runlist-gk20a diff --git a/userspace/SWUTS.sources b/userspace/SWUTS.sources index 7cf21507b..2e3408c44 100644 --- a/userspace/SWUTS.sources +++ b/userspace/SWUTS.sources @@ -17,6 +17,7 @@ INPUT += ../../../userspace/units/fifo/engine/gp10b/nvgpu-engine-gp10b.h INPUT += ../../../userspace/units/fifo/engine/gv100/nvgpu-engine-gv100.h INPUT += ../../../userspace/units/fifo/engine/gv11b/nvgpu-engine-gv11b.h INPUT += ../../../userspace/units/fifo/pbdma/nvgpu-pbdma.h +INPUT += ../../../userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.h INPUT += ../../../userspace/units/fifo/pbdma/gv11b/nvgpu-pbdma-gv11b.h INPUT += ../../../userspace/units/fifo/runlist/nvgpu-runlist.h INPUT += ../../../userspace/units/fifo/runlist/gk20a/nvgpu-runlist-gk20a.h diff --git a/userspace/units/fifo/pbdma/gm20b/Makefile b/userspace/units/fifo/pbdma/gm20b/Makefile new file mode 100644 index 000000000..d7265ee71 --- /dev/null +++ b/userspace/units/fifo/pbdma/gm20b/Makefile @@ -0,0 +1,32 @@ +# 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-pbdma-gm20b.o +MODULE = nvgpu-pbdma-gm20b + +LIB_PATHS += -lnvgpu-fifo +include ../../../Makefile.units + +lib$(MODULE).so: fifo + +fifo: + $(MAKE) -C ../.. diff --git a/userspace/units/fifo/pbdma/gm20b/Makefile.interface.tmk b/userspace/units/fifo/pbdma/gm20b/Makefile.interface.tmk new file mode 100644 index 000000000..fc6d57533 --- /dev/null +++ b/userspace/units/fifo/pbdma/gm20b/Makefile.interface.tmk @@ -0,0 +1,35 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# 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. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=nvgpu-pbdma-gm20b + +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/pbdma/gm20b/Makefile.tmk b/userspace/units/fifo/pbdma/gm20b/Makefile.tmk new file mode 100644 index 000000000..a177649f6 --- /dev/null +++ b/userspace/units/fifo/pbdma/gm20b/Makefile.tmk @@ -0,0 +1,40 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# 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. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME = nvgpu-pbdma-gm20b +NVGPU_UNIT_SRCS = nvgpu-pbdma-gm20b.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/pbdma/gm20b/nvgpu-pbdma-gm20b.c b/userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.c new file mode 100644 index 000000000..ff422d8f6 --- /dev/null +++ b/userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.c @@ -0,0 +1,538 @@ +/* + * 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 + +#include "hal/fifo/pbdma_gm20b.h" + +#include + +#include "../../nvgpu-fifo.h" +#include "../../nvgpu-fifo-gv11b.h" +#include "nvgpu-pbdma-gm20b.h" + +#ifdef PBDMA_GM20B_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 assert(cond) unit_assert(cond, goto done) + +#define branches_str test_fifo_flags_str +#define pruned test_fifo_subtest_pruned + +struct unit_ctx { + struct unit_module *m; + u32 branches; + struct { + struct { + u32 count; + } pbdma_handle_intr_0; + struct { + u32 count; + } pbdma_handle_intr_1; + } stubs; +}; + +static struct unit_ctx u; + +static void subtest_setup(struct unit_module *m, u32 branches) +{ + u.m = m; + u.branches = branches; + memset(&u.stubs, 0, sizeof(u.stubs)); +} + +static u32 _man(u32 timeout) +{ + return (timeout & pbdma_acquire_timeout_man_max_f()) >> 15; +} + +static u32 _exp(u32 timeout) +{ + return (timeout & pbdma_acquire_timeout_exp_max_f()) >> 11; +} + +static bool is_timeout_valid(struct unit_module *m, u32 timeout, u64 ms) { + + u64 man = _man(timeout); + u64 exp = _exp(timeout); + u64 actual_ns = (1024UL * (u64)man) << (u64)exp; + u64 expected_ns; + u64 delta; + u64 max_delta = (1024UL << exp); + u64 max_ns = ((1024UL * (u64)pbdma_acquire_timeout_man_max_v()) << + pbdma_acquire_timeout_exp_max_v()); + + assert((timeout & 0x3ff) == + (pbdma_acquire_retry_man_2_f() | pbdma_acquire_retry_exp_2_f())); + if (ms == 0) { + assert((timeout & pbdma_acquire_timeout_en_enable_f()) == 0); + return true; + } else { + assert((timeout & pbdma_acquire_timeout_en_enable_f()) != 0); + } + + unit_verbose(m, "ms = %llu\n", ms); + unit_verbose(m, "max_ns = %llu\n", max_ns); + + expected_ns = (ms * 80 * 1000000UL) / 100; + expected_ns = min(expected_ns, max_ns); + unit_verbose(m, "expected_ns = %llu\n", expected_ns); + unit_verbose(m, "actual_ns = %llu\n", actual_ns); + + unit_verbose(m, "man = %x\n", (u32)man); + unit_verbose(m, "exp = %x\n", (u32)exp); + + delta = (expected_ns > actual_ns ? + expected_ns - actual_ns : actual_ns - expected_ns); + unit_verbose(m, "max delta = %llu\n", max_delta); + unit_verbose(m, "delta = %llu\n", delta); + assert(delta < max_delta); + + return true; +done: + return false; +} + +int test_gm20b_pbdma_acquire_val(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + u32 timeout; + u64 ms; + int i; + int err; + + for (i = 0; i < 32; i++) { + ms = (1ULL << i); + timeout = gm20b_pbdma_acquire_val(ms); + assert(is_timeout_valid(m, timeout, ms)); + } + + err = EXPECT_BUG(gm20b_pbdma_acquire_val(U64_MAX)); + assert(err != 0); + + ret = UNIT_SUCCESS; +done: + + return ret; +} + +#define F_PBDMA_HANDLE_INTR_0_PENDING BIT(0) +#define F_PBDMA_HANDLE_INTR_0_RECOVER BIT(1) +#define F_PBDMA_HANDLE_INTR_1_PENDING BIT(2) +#define F_PBDMA_HANDLE_INTR_1_RECOVER BIT(3) +#define F_PBDMA_HANDLE_INTR_ERR_NOTIFIER BIT(4) +#define F_PBDMA_HANDLE_INTR_LAST BIT(5) + +#define INVALID_ERR_NOTIFIER U32_MAX + +static bool stub_pbdma_handle_intr_0(struct gk20a *g, + u32 pbdma_id, u32 pbdma_intr_0, u32 *error_notifier) +{ + u.stubs.pbdma_handle_intr_0.count++; + + if (u.branches & F_PBDMA_HANDLE_INTR_0_RECOVER) { + return true; + } + return false; +} + +static bool stub_pbdma_handle_intr_1(struct gk20a *g, + u32 pbdma_id, u32 pbdma_intr_1, u32 *error_notifier) +{ + u.stubs.pbdma_handle_intr_1.count++; + if (u.branches & F_PBDMA_HANDLE_INTR_1_RECOVER) { + return true; + } + return false; +} + +int test_gm20b_pbdma_handle_intr(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + struct gpu_ops gops = g->ops; + u32 branches; + const char *labels[] = { + "intr_0_pending", + "intr_0_recover", + "intr_1_pending", + "intr_1_recover", + "err_notifier", + }; + u32 pbdma_id = 0; + u32 _err_notifier; + u32 *err_notifier; + struct nvgpu_pbdma_status_info pbdma_status; + bool recover; + + g->ops.pbdma.handle_intr_0 = stub_pbdma_handle_intr_0; + g->ops.pbdma.handle_intr_1 = stub_pbdma_handle_intr_1; + + for (branches = 0; branches < F_PBDMA_HANDLE_INTR_LAST; branches++) { + + subtest_setup(m, branches); + unit_verbose(m, "%s branches=%s\n", __func__, + branches_str(branches, labels)); + + err_notifier = branches & F_PBDMA_HANDLE_INTR_ERR_NOTIFIER ? + &_err_notifier : NULL; + _err_notifier = INVALID_ERR_NOTIFIER; + + nvgpu_writel(g, pbdma_intr_0_r(pbdma_id), 0); + nvgpu_writel(g, pbdma_intr_1_r(pbdma_id), 0); + + if (branches & F_PBDMA_HANDLE_INTR_0_PENDING) { + nvgpu_writel(g, pbdma_intr_0_r(pbdma_id), BIT(0)); + } + + if (branches & F_PBDMA_HANDLE_INTR_1_PENDING) { + nvgpu_writel(g, pbdma_intr_1_r(pbdma_id), BIT(0)); + } + + recover = gm20b_pbdma_handle_intr(g, pbdma_id, err_notifier, &pbdma_status); + + if (branches & F_PBDMA_HANDLE_INTR_0_PENDING) { + assert(u.stubs.pbdma_handle_intr_0.count > 0); + if (branches & F_PBDMA_HANDLE_INTR_0_RECOVER) { + assert(recover); + } + } + + if (branches & F_PBDMA_HANDLE_INTR_1_PENDING) { + assert(u.stubs.pbdma_handle_intr_1.count > 0); + if (branches & F_PBDMA_HANDLE_INTR_1_RECOVER) { + assert(recover); + } + } + + if (branches & F_PBDMA_HANDLE_INTR_ERR_NOTIFIER) { + assert(*err_notifier != INVALID_ERR_NOTIFIER); + } + + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, labels)); + } + g->ops = gops; + return ret; +} + +#define PBDMA_NUM_INTRS 6 + +#define METHOD_NO_SUBCH 0 +#define METHOD_SUBCH5 (5 << 16) +#define METHOD_SUBCH6 (6 << 16) +#define METHOD_SUBCH7 (7 << 16) + +int test_gm20b_pbdma_handle_intr_0(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + struct nvgpu_fifo *f = &g->fifo; + struct gpu_ops gops = g->ops; + u32 branches = 0; + u32 pbdma_intrs[PBDMA_NUM_INTRS] = { + pbdma_intr_0_memreq_pending_f(), + pbdma_intr_0_acquire_pending_f(), + pbdma_intr_0_pbentry_pending_f(), + pbdma_intr_0_method_pending_f(), + pbdma_intr_0_pbcrc_pending_f(), + pbdma_intr_0_device_pending_f() + }; + const char *labels[] = { + "memreq", + "acquire", + "pbentry", + "method", + "pbcrc", + "device", + }; + u32 pbdma_id = 0; + u32 pbdma_intr_0; + u32 err_notifier; + bool recover; + int i; + + assert((f->intr.pbdma.device_fatal_0 & pbdma_intr_0_memreq_pending_f()) != 0); + + for (branches = 0; branches < BIT(PBDMA_NUM_INTRS); branches++) { + + subtest_setup(m, branches); + unit_verbose(m, "%s branches=%s\n", __func__, + branches_str(branches, labels)); + + pbdma_intr_0 = 0; + for (i = 0; i < PBDMA_NUM_INTRS; i++) { + if (branches & BIT(i)) { + pbdma_intr_0 |= pbdma_intrs[i]; + } + } + err_notifier = INVALID_ERR_NOTIFIER; + + nvgpu_writel(g, pbdma_intr_0_r(pbdma_id), pbdma_intr_0); + nvgpu_writel(g, pbdma_method0_r(pbdma_id), METHOD_SUBCH5); + nvgpu_writel(g, pbdma_method1_r(pbdma_id), METHOD_NO_SUBCH); + nvgpu_writel(g, pbdma_method2_r(pbdma_id), METHOD_SUBCH6); + nvgpu_writel(g, pbdma_method3_r(pbdma_id), METHOD_SUBCH7); + nvgpu_writel(g, pbdma_pb_header_r(pbdma_id), 0); + + recover = gm20b_pbdma_handle_intr_0(g, pbdma_id, pbdma_intr_0, &err_notifier); + + if (pbdma_intr_0 == 0) { + assert(!recover); + } + + if (pbdma_intr_0 & pbdma_intr_0_memreq_pending_f()) { + assert(recover); + } + + if (pbdma_intr_0 & pbdma_intr_0_acquire_pending_f()) { + if (nvgpu_is_timeouts_enabled(g)) { + assert(recover); + assert(err_notifier != INVALID_ERR_NOTIFIER); + } else { + assert(!recover); + } + } + + if (pbdma_intr_0 & pbdma_intr_0_pbentry_pending_f()) { + assert(recover); + assert(nvgpu_readl(g, pbdma_pb_header_r(pbdma_id)) != 0); + assert(nvgpu_readl(g, pbdma_method0_r(pbdma_id)) != METHOD_SUBCH5); + } + + if (pbdma_intr_0 & pbdma_intr_0_method_pending_f()) { + assert(recover); + assert(nvgpu_readl(g, pbdma_method0_r(pbdma_id)) != METHOD_SUBCH5); + } + + if (pbdma_intr_0 & pbdma_intr_0_pbcrc_pending_f()) { + assert(recover); + assert(err_notifier != INVALID_ERR_NOTIFIER); + } + + if (pbdma_intr_0 & pbdma_intr_0_device_pending_f()) { + assert(recover); + assert(nvgpu_readl(g, pbdma_pb_header_r(pbdma_id)) != 0); + assert(nvgpu_readl(g, pbdma_method0_r(pbdma_id)) != METHOD_SUBCH5); + assert(nvgpu_readl(g, pbdma_method1_r(pbdma_id)) == METHOD_NO_SUBCH); + assert(nvgpu_readl(g, pbdma_method2_r(pbdma_id)) != METHOD_SUBCH6); + assert(nvgpu_readl(g, pbdma_method3_r(pbdma_id)) != METHOD_SUBCH7); + } + + } + + ret = UNIT_SUCCESS; +done: + if (ret != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, labels)); + } + g->ops = gops; + return ret; +} + +int test_gm20b_pbdma_read_data(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + struct nvgpu_fifo *f = &g->fifo; + u32 pbdma_id = 0; + + for (pbdma_id = 0; pbdma_id < f->num_pbdma; pbdma_id++) { + u32 pattern = (0xbeef << 16) + pbdma_id; + nvgpu_writel(g, pbdma_hdr_shadow_r(pbdma_id), pattern); + assert(gm20b_pbdma_read_data(g, pbdma_id) == pattern); + } + + ret = UNIT_SUCCESS; +done: + return ret; +} + +int test_gm20b_pbdma_intr_descs(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + struct nvgpu_fifo *f = &g->fifo; + u32 intr_descs = (f->intr.pbdma.device_fatal_0 | + f->intr.pbdma.channel_fatal_0 | + f->intr.pbdma.restartable_0); + u32 fatal_0 = gm20b_pbdma_device_fatal_0_intr_descs(); + u32 restartable_0 = gm20b_pbdma_restartable_0_intr_descs(); + + assert(fatal_0 != 0); + assert(restartable_0 != 0); + assert((intr_descs & fatal_0) == fatal_0); + assert((intr_descs & restartable_0) == restartable_0); + + ret = UNIT_SUCCESS; +done: + return ret; +} + +int test_gm20b_pbdma_format_gpfifo_entry(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + struct nvgpu_gpfifo_entry gpfifo_entry; + u64 pb_gpu_va = 0x12deadbeefULL; + u32 method_size = 5; + + memset(&gpfifo_entry, 0, sizeof(gpfifo_entry)); + gm20b_pbdma_format_gpfifo_entry(g, &gpfifo_entry, pb_gpu_va, method_size); + assert(gpfifo_entry.entry0 == 0xdeadbeef); + assert(gpfifo_entry.entry1 == (0x12 | pbdma_gp_entry1_length_f(method_size))); + + ret = UNIT_SUCCESS; +done: + return ret; +} + +int test_gm20b_pbdma_get_gp_base(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + u64 gpfifo_base = 0x12deadbeefULL; + u32 base_lo; + u32 base_hi; + u32 n; + int err; + + err = EXPECT_BUG(gm20b_pbdma_get_gp_base_hi(gpfifo_base, 0)); + assert(err != 0); + + for (n = 1; n < 16; n++) { + base_lo = gm20b_pbdma_get_gp_base(gpfifo_base); + base_hi = gm20b_pbdma_get_gp_base_hi(gpfifo_base, 1 << n); + assert(base_lo == pbdma_gp_base_offset_f( + u64_lo32(gpfifo_base >> pbdma_gp_base_rsvd_s()))); + assert(base_hi == + (pbdma_gp_base_hi_offset_f(u64_hi32(gpfifo_base)) | + pbdma_gp_base_hi_limit2_f(n))); + } + + ret = UNIT_SUCCESS; +done: + return ret; +} + +#define PBDMA_SUBDEVICE_ID 1U + +int test_gm20b_pbdma_get_fc_subdevice(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + + assert(gm20b_pbdma_get_fc_subdevice() == + (pbdma_subdevice_id_f(PBDMA_SUBDEVICE_ID) | + pbdma_subdevice_status_active_f() | + pbdma_subdevice_channel_dma_enable_f())); + + ret = UNIT_SUCCESS; +done: + return ret; +} + +int test_gm20b_pbdma_get_userd(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = UNIT_FAIL; + u32 addr_lo = 0xdeadbeef; + u32 addr_hi = 0x12; + struct nvgpu_mem mem; + u32 mask = 0xaaaa; + int err; + + assert(gm20b_pbdma_get_userd_addr(addr_lo) == pbdma_userd_addr_f(addr_lo)); + assert(gm20b_pbdma_get_userd_hi_addr(addr_hi) == pbdma_userd_hi_addr_f(addr_hi)); + + mem.aperture = APERTURE_INVALID; + err = EXPECT_BUG(mask = gm20b_pbdma_get_userd_aperture_mask(g, &mem)); + assert(err != 0); + assert(mask == 0xaaaa); + + if (nvgpu_is_enabled(g, NVGPU_MM_HONORS_APERTURE)) { + mem.aperture = APERTURE_SYSMEM; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_sys_mem_ncoh_f()); + mem.aperture = APERTURE_SYSMEM_COH; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_sys_mem_coh_f()); + mem.aperture = APERTURE_VIDMEM; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_vid_mem_f()); + } else { + mem.aperture = APERTURE_SYSMEM; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_vid_mem_f()); + mem.aperture = APERTURE_SYSMEM_COH; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_vid_mem_f()); + mem.aperture = APERTURE_VIDMEM; + assert(gm20b_pbdma_get_userd_aperture_mask(g, &mem) == pbdma_userd_target_vid_mem_f()); + } + + ret = UNIT_SUCCESS; +done: + return ret; +} + + +struct unit_module_test nvgpu_pbdma_gm20b_tests[] = { + UNIT_TEST(init_support, test_fifo_init_support, NULL, 0), + UNIT_TEST(pbdma_acquire_val, test_gm20b_pbdma_acquire_val, NULL, 0), + UNIT_TEST(pbdma_handle_intr, test_gm20b_pbdma_handle_intr, NULL, 0), + UNIT_TEST(pbdma_handle_intr_0, test_gm20b_pbdma_handle_intr_0, NULL, 0), + UNIT_TEST(pbdma_read_data, test_gm20b_pbdma_read_data, NULL, 0), + UNIT_TEST(pbdma_intr_descs, test_gm20b_pbdma_intr_descs, NULL, 0), + UNIT_TEST(pbdma_format_gpfifo_entry, test_gm20b_pbdma_format_gpfifo_entry, NULL, 0), + UNIT_TEST(pbdma_get_gp_base, test_gm20b_pbdma_get_gp_base, NULL, 0), + UNIT_TEST(pbdma_get_fc_subdevice, test_gm20b_pbdma_get_fc_subdevice, NULL, 0), + UNIT_TEST(pbdma_get_userd, test_gm20b_pbdma_get_userd, NULL, 0), + UNIT_TEST(remove_support, test_fifo_remove_support, NULL, 0), +}; + +UNIT_MODULE(nvgpu_pbdma_gm20b, nvgpu_pbdma_gm20b_tests, UNIT_PRIO_NVGPU_TEST); diff --git a/userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.h b/userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.h new file mode 100644 index 000000000..87d266d4e --- /dev/null +++ b/userspace/units/fifo/pbdma/gm20b/nvgpu-pbdma-gm20b.h @@ -0,0 +1,266 @@ +/* + * 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_PBDMA_GM20B_H +#define UNIT_NVGPU_PBDMA_GM20B_H + +#include + +struct unit_module; +struct gk20a; + +/** @addtogroup SWUTS-fifo-pbdma-gm20b + * @{ + * + * Software Unit Test Specification for fifo/pbdma/gm20b + */ + +/** + * Test specification for: test_gm20b_pbdma_acquire_val + * + * Description: Branch coverage for PBDMA acquire timeout. + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_acquire_val + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Acquire timeout varying from 0 to 2^32 ms. + * - Compute expected value in ns. It should be the minimum of: + * - 80% of requested timeout. + * - maximum timeout that can be specified with mantissa and exponent. + * - Compute actual value in ns from mantissa and exponent. + * - Check that delta between expected and actual values is lower than + * 1024 * (1 << exponent). + * - Check that BUG_ON occurs on overflow while converting ms to ns. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_acquire_val(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_handle_intr + * + * Description: Branch coverage for PBDMA interrupt handler + * + * Targets: gm20b_pbdma_handle_intr + * + * Test Type: Feature based + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Set pbdma_intr_0_r and pbdma_intr_1_r registers. + * - Check cases where stalling interrupts are pending: + * - Set pbdma_intr_0_r to non-zero value. + * - Check that handle_intr_0 is called using stub. + * - Check that read_pbdma_status_info is called when + * handle_intr_0 returns true (recovery needed). + * - Check cases where non-stalling interrupts are pending: + * - Set pbdma_intr_1_r to non-zero value. + * - Check that handle_intr_1 is called using stub. + * - Check that read_pbdma_status_info is called when + * handle_intr_1 returns true (recovery needed). + * - Check that error notifier is set, when provided. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_handle_intr(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_handle_intr_0 + * + * Description: Branch coverage for PBDMA stalling interrupt handler + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_handle_intr_0, gm20b_pbdma_reset_header + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Set pbdma_intr_0 and check interrupt handling for combinations of + * the following interrupts: + * - pbdma_intr_0_memreq: Check that recover is true. + * - pbdma_intr_0_acquire: Check that recover is true when timeouts are + * enabled, false otherwise. Check that error notifier is set when + * timeouts are enable. + * - pbdma_intr_0_pbentry: Check that pbdma method0 and headers have been + * reset, and that recover is true. + * - pbdma_intr_0_method: Check that method0 has been reset, and that + * recover is true. + * - pbdma_intr_0_pbcrc: Check that recover is true and that error notifier + * has been set. + * - pbdma_intr_0_device: Check that all pbdma subch methods and header + * have been reset and that recover is true. + * - Check that recover is false, when none of above interrupt is raised. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_handle_intr_0(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_read_data + * + * Description: Branch coverage for reading PBDMA header shadow. + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_read_data + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - For each H/W PBDMA id, set pbdma_hdr_shadow_r(pbdma_id) with a pattern, + * and read it back with gm20b_pbdma_read_data. + * - Check that value matches pattern. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_read_data(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_intr_descs + * + * Description: Branch coverage for interrupt descriptors. + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_device_fatal_0_intr_descs, + * gm20b_pbdma_restartable_0_intr_descs. + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Check that g->fifo->intr_descs contains the interrupts + * specified in gm20b_pbdma_device_fatal_0_intr_descs and + * gm20b_pbdma_restartable_0_intr_descs. + * - Check that fatal_0 and restartable_0 interrupts masks are non-zero. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_intr_descs(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_format_gpfifo_entry + * + * Description: Format a GPFIFO entry. + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_format_gpfifo_entry + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Zero-initialize a gpfifo_entry then call gm20b_pbdma_format_gpfifo_entry + * with dummy pb_gpu_va and method_size. + * - Check that pb_gpu_va and method_size are properly encoded in + * gp_fifo_entry.entry0 and gp_fifo_entry.entry1. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_format_gpfifo_entry(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_get_gp_base + * + * Description: Branch coverage for GPFIFO base. + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_get_gp_base, test_gm20b_pbdma_get_gp_base_hi + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Check that BUG() is raised when invoking gm20b_pbdma_get_gp_base_hi + * with 0 gpfifo_entry (because of ilog2). + * - For each power of 2 between 1 and 16: + * - Call gm20b_pbdma_get_gp_base and gm20b_pbdma_get_gp_base_hi with + * dummy gpfifo_base. + * - Check that address and number of entries are properly encoded. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_get_gp_base(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_get_fc_subdevice + * + * Description: Check RAMFC wrappers for instance block init + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_get_fc_subdevice + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Check that value returned by test_gm20b_pbdma_get_fc_subdevice is + * consistent with H/W manuals. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_get_fc_subdevice(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for: test_gm20b_pbdma_get_userd_addr + * + * Description: Check USERD HALs for instance block init + * + * Test Type: Feature based + * + * Targets: gm20b_pbdma_get_userd_addr, gm20b_pbdma_get_userd_hi_addr, + * gm20b_pbdma_get_userd_aperture_mask + * + * Input: test_fifo_init_support() run for this GPU + * + * Steps: + * - Check that lo and hi addresses returned by gm20b_pbdma_get_userd_addr and + * gm20b_pbdma_get_userd_hi_addr match format from H/W manuals. + * - Check that BUG() is returned when gm20b_pbdma_get_userd_aperture_mask + * is called with and invalid aperture. + * - Check aperture masks returned by gm20b_pbdma_get_userd_aperture_mask + * for APERTURE_SYSMEM, APERTURE_SYSMEM_COH and APERTURE_VIDMEM. + * - Check that aperture mask is always pbdma_userd_target_vid_mem_f() when + * NVGPU_MM_HONORS_APERTURE is false. + * + * Output: Returns PASS if all branches gave expected results. FAIL otherwise. + */ +int test_gm20b_pbdma_get_userd(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * @} + */ + +#endif /* UNIT_NVGPU_PBDMA_GM20B_H */