From 1eef4eaae586a57765989bdcf1104ceee516ba27 Mon Sep 17 00:00:00 2001 From: Thomas Fleury Date: Thu, 23 May 2019 16:33:17 -0700 Subject: [PATCH] gpu: nvgpu: unit: add channel open tests Add unit test for: - gk20a_channel_open_new Jira NVGPU-3480 Change-Id: I50d8cef746aa532712c94a3806822f5f0c7f435f Signed-off-by: Thomas Fleury Reviewed-on: https://git-master.nvidia.com/r/2129723 GVS: Gerrit_Virtual_Submit Reviewed-by: Alex Waterman Reviewed-by: mobile promotions Tested-by: mobile promotions --- userspace/units/fifo/channel/nvgpu-channel.c | 182 +++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/userspace/units/fifo/channel/nvgpu-channel.c b/userspace/units/fifo/channel/nvgpu-channel.c index 2353b326f..104e4dbd4 100644 --- a/userspace/units/fifo/channel/nvgpu-channel.c +++ b/userspace/units/fifo/channel/nvgpu-channel.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -35,17 +36,25 @@ #include "../nvgpu-fifo.h" +#define MAX_STUB 2 + +struct stub_ctx { + u32 chid; +}; struct stub_ctx stub[MAX_STUB]; struct channel_unit_ctx { u32 branches; + struct stub_ctx stub[MAX_STUB]; }; static struct channel_unit_ctx unit_ctx; static void subtest_setup(u32 branches) { + u32 i; + unit_ctx.branches = branches; memset(stub, 0, sizeof(stub)); for (i = 0; i < MAX_STUB; i++) { @@ -129,9 +138,182 @@ done: return rc; } +#define F_CHANNEL_OPEN_ENGINE_NOT_VALID BIT(0) +#define F_CHANNEL_OPEN_PRIVILEGED BIT(1) +#define F_CHANNEL_OPEN_ALLOC_CH_FAIL BIT(2) +#define F_CHANNEL_OPEN_ALLOC_CH_WARN0 BIT(3) +#define F_CHANNEL_OPEN_ALLOC_CH_WARN1 BIT(4) +#define F_CHANNEL_OPEN_ALLOC_CH_AGGRESSIVE BIT(5) +#define F_CHANNEL_OPEN_BUG_ON BIT(6) +#define F_CHANNEL_OPEN_ALLOC_INST_FAIL BIT(7) +#define F_CHANNEL_OPEN_OS BIT(8) +#define F_CHANNEL_OPEN_LAST BIT(9) + + +/* TODO: cover nvgpu_cond_init failures */ +#define F_CHANNEL_OPEN_COND0_INIT_FAIL +#define F_CHANNEL_OPEN_COND1_INIT_FAIL + +static const char *f_channel_open[] = { + "engine_not_valid", + "privileged", + "alloc_ch_fail", + "alloc_ch_warn0", + "alloc_ch_warn1", + "aggressive_destroy", + "bug_on", + "alloc_inst_fail", + "cond0_init_fail", + "cond1_init_fail", + "hal", +}; + +static int stub_channel_alloc_inst_ENOMEM(struct gk20a *g, + struct nvgpu_channel *ch) +{ + return -ENOMEM; +} + +static int test_channel_open(struct unit_module *m, + struct gk20a *g, void *args) +{ + struct nvgpu_fifo *f = &g->fifo; + struct nvgpu_fifo fifo = g->fifo; + struct gpu_ops gops = g->ops; + struct nvgpu_channel *ch, *next_ch; + struct nvgpu_posix_fault_inj *kmem_fi; + u32 branches; + int rc = UNIT_FAIL; + u32 fail = + F_CHANNEL_OPEN_ALLOC_CH_FAIL | + F_CHANNEL_OPEN_BUG_ON | + F_CHANNEL_OPEN_ALLOC_INST_FAIL; + u32 prune = fail | + F_CHANNEL_OPEN_ALLOC_CH_WARN0 | + F_CHANNEL_OPEN_ALLOC_CH_WARN1; + u32 runlist_id; + bool privileged; + int err; + void (*os_channel_open)(struct nvgpu_channel *ch) = + g->os_channel.open; + + kmem_fi = nvgpu_kmem_get_fault_injection(); + + for (branches = 0U; branches < F_CHANNEL_OPEN_LAST; branches++) { + + if (subtest_pruned(branches, prune)) { + unit_verbose(m, "%s branches=%s (pruned)\n", __func__, + branches_str(branches, f_channel_open)); + continue; + } + subtest_setup(branches); + unit_verbose(m, "%s branches=%s\n", __func__, + branches_str(branches, f_channel_open)); + + nvgpu_posix_enable_fault_injection(kmem_fi, false, 0); + + next_ch = + nvgpu_list_empty(&f->free_chs) ? NULL : + nvgpu_list_first_entry(&f->free_chs, + nvgpu_channel, free_chs); + assert(next_ch != NULL); + + runlist_id = + branches & F_CHANNEL_OPEN_ENGINE_NOT_VALID ? + NVGPU_INVALID_RUNLIST_ID : + NVGPU_ENGINE_GR; + + privileged = + branches & F_CHANNEL_OPEN_PRIVILEGED ? + true : false; + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_FAIL) { + nvgpu_init_list_node(&f->free_chs); + } + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_WARN0) { + nvgpu_atomic_inc(&next_ch->ref_count); + } + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_WARN1) { + next_ch->referenceable = false; + } + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_AGGRESSIVE) { + g->aggressive_sync_destroy_thresh += 1U; + f->used_channels += 2U; + } + + g->ops.channel.alloc_inst = + branches & F_CHANNEL_OPEN_ALLOC_INST_FAIL ? + stub_channel_alloc_inst_ENOMEM : + gops.channel.alloc_inst; + + if (branches & F_CHANNEL_OPEN_BUG_ON) { + next_ch->g = (void *)1; + } + + err = EXPECT_BUG( + ch = gk20a_open_new_channel(g, runlist_id, + privileged, getpid(), getpid()); + ); + + if (branches & F_CHANNEL_OPEN_BUG_ON) { + next_ch->g = NULL; + assert(err != 0); + } else { + assert(err == 0); + }; + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_WARN1) { + next_ch->referenceable = true; + } + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_AGGRESSIVE) { + g->aggressive_sync_destroy_thresh -= 1U; + f->used_channels -= 2U; + assert(g->aggressive_sync_destroy); + g->aggressive_sync_destroy = false; + } + + if (branches & fail) { + if (branches & F_CHANNEL_OPEN_ALLOC_CH_FAIL) { + f->free_chs = fifo.free_chs; + } + + if (branches & F_CHANNEL_OPEN_ALLOC_CH_WARN0) { + nvgpu_atomic_dec(&ch->ref_count); + } + assert(ch == NULL); + } else { + assert(ch != NULL); + assert(ch->g == g); + assert(nvgpu_list_empty(&ch->free_chs)); + + nvgpu_channel_close(ch); + ch = NULL; + } + } + rc = UNIT_SUCCESS; + +done: + if (rc != UNIT_SUCCESS) { + unit_err(m, "%s branches=%s\n", __func__, + branches_str(branches, f_channel_open)); + } + nvgpu_posix_enable_fault_injection(kmem_fi, false, 0); + if (ch != NULL) { + nvgpu_channel_close(ch); + } + g->ops = gops; + g->os_channel.open = os_channel_open; + return rc; +} + struct unit_module_test nvgpu_channel_tests[] = { UNIT_TEST(setup_sw, test_channel_setup_sw, &unit_ctx, 0), UNIT_TEST(init_support, test_fifo_init_support, &unit_ctx, 0), + UNIT_TEST(open, test_channel_open, &unit_ctx, 0), UNIT_TEST(remove_support, test_fifo_remove_support, &unit_ctx, 0), };