gpu: nvgpu: modify wait_pending

The wait_pending HAL is now modified to simply
check the pending status of a given runlist.
The while loop is removed from this HAL.

A new function nvgpu_runlist_wait_pending_legacy() is
added that emulates the older wait_pending() HAL.

nvgpu_runlist_tick() is modified to accept a 64 bit
"preempt_grace_ns" value.

These changes prepare for upcoming control-fifo parser
changes.

Jira NVGPU-8619

Signed-off-by: Debarshi Dutta <ddutta@nvidia.com>
Change-Id: If3f288eb6f2181743c53b657219b3b30d56d26bc
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2766100
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Debarshi Dutta
2022-08-24 16:58:05 +05:30
committed by mobile promotions
parent 1e2817e022
commit 143034daab
23 changed files with 122 additions and 127 deletions

View File

@@ -453,11 +453,31 @@ void nvgpu_runlist_swap_mem(struct gk20a *g, struct nvgpu_runlist_domain *domain
nvgpu_spinlock_release(&domain->lock);
}
static int nvgpu_runlist_domain_actual_submit(struct gk20a *g, struct nvgpu_runlist *rl,
bool wait_for_finish)
int nvgpu_runlist_wait_pending_legacy(struct gk20a *g, struct nvgpu_runlist *rl)
{
int ret = 0;
struct nvgpu_timeout timeout;
u32 delay = POLL_DELAY_MIN_US;
int ret;
nvgpu_timeout_init_cpu_timer(g, &timeout, nvgpu_get_poll_timeout(g));
ret = -ETIMEDOUT;
do {
if (g->ops.runlist.check_pending(g, rl) == 0) {
ret = 0;
break;
}
/* Avoid sleeping */
nvgpu_usleep_range(delay, delay * 2U);
delay = min_t(u32, delay << 1, POLL_DELAY_MAX_US);
} while (nvgpu_timeout_expired(&timeout) == 0);
return ret;
}
static void nvgpu_runlist_domain_actual_submit(struct gk20a *g, struct nvgpu_runlist *rl)
{
rl_dbg(g, "Runlist[%u]: submitting domain[%llu]",
rl->id, rl->domain->domain_id);
@@ -467,18 +487,6 @@ static int nvgpu_runlist_domain_actual_submit(struct gk20a *g, struct nvgpu_runl
nvgpu_spinlock_acquire(&rl->domain->lock);
g->ops.runlist.hw_submit(g, rl);
nvgpu_spinlock_release(&rl->domain->lock);
if (wait_for_finish) {
ret = g->ops.runlist.wait_pending(g, rl);
if (ret == -ETIMEDOUT) {
nvgpu_err(g, "runlist %d update timeout", rl->id);
/* trigger runlist update timeout recovery */
return ret;
}
}
return ret;
}
static int nvgpu_runlist_update_mem_locked(struct gk20a *g, struct nvgpu_runlist *rl,
@@ -594,7 +602,7 @@ int nvgpu_runlist_reschedule(struct nvgpu_channel *ch, bool preempt_next,
}
}
if (g->ops.runlist.wait_pending(g, runlist) != 0) {
if (nvgpu_runlist_wait_pending_legacy(g, runlist) != 0) {
nvgpu_err(g, "wait pending failed for runlist %u",
runlist->id);
}
@@ -668,19 +676,15 @@ static int nvgpu_runlist_do_update(struct gk20a *g, struct nvgpu_runlist *rl,
/*
* This is expected to be called only when device is powered on.
*/
static int runlist_submit_powered(struct gk20a *g, struct nvgpu_runlist *runlist,
struct nvgpu_runlist_domain *next_domain, bool wait_for_finish)
static void runlist_submit_powered(struct gk20a *g, struct nvgpu_runlist *runlist,
struct nvgpu_runlist_domain *next_domain)
{
int err;
runlist->domain = next_domain;
rl_dbg(g, "Runlist[%u]: switching to domain %llu",
runlist->id, next_domain->domain_id);
err = nvgpu_runlist_domain_actual_submit(g, runlist, wait_for_finish);
return err;
nvgpu_runlist_domain_actual_submit(g, runlist);
}
int nvgpu_rl_domain_sync_submit(struct gk20a *g, struct nvgpu_runlist *runlist,
@@ -692,26 +696,28 @@ int nvgpu_rl_domain_sync_submit(struct gk20a *g, struct nvgpu_runlist *runlist,
next_domain = runlist->shadow_rl_domain;
}
err = runlist_submit_powered(g, runlist, next_domain, wait_for_finish);
runlist_submit_powered(g, runlist, next_domain);
if (wait_for_finish) {
err = nvgpu_runlist_wait_pending_legacy(g, runlist);
if (err != 0) {
nvgpu_err(g, "runlist %d update timeout", runlist->id);
/* trigger runlist update timeout recovery */
return err;
}
}
return err;
}
static int runlist_switch_domain_and_submit(struct gk20a *g,
struct nvgpu_runlist *runlist, struct nvgpu_runlist_domain *rl_domain)
{
int ret = 0;
ret = runlist_submit_powered(g, runlist, rl_domain, false);
return ret;
}
void nvgpu_runlist_tick(struct gk20a *g, struct nvgpu_runlist_domain **rl_domain)
int nvgpu_runlist_tick(struct gk20a *g, struct nvgpu_runlist_domain **rl_domain,
u64 preempt_grace_ns)
{
struct nvgpu_fifo *f = &g->fifo;
u32 i;
int err = 0;
int ret = 0;
int err = -ETIMEDOUT;
u64 start_time = nvgpu_safe_cast_s64_to_u64(nvgpu_current_time_ns());
u64 current_time;
rl_dbg(g, "domain tick");
@@ -719,11 +725,23 @@ void nvgpu_runlist_tick(struct gk20a *g, struct nvgpu_runlist_domain **rl_domain
struct nvgpu_runlist *runlist;
runlist = &f->active_runlists[i];
err = runlist_switch_domain_and_submit(g, runlist, rl_domain[i]);
if (err != 0) {
nvgpu_err(g, "Failed to schedule domain [%llu]", rl_domain[i]->domain_id);
}
runlist_submit_powered(g, runlist, rl_domain[i]);
do {
ret = g->ops.runlist.check_pending(g, runlist);
if (ret == 0) {
break;
}
current_time = nvgpu_safe_cast_s64_to_u64(nvgpu_current_time_ns());
} while ((preempt_grace_ns == 0ULL)
|| (nvgpu_safe_sub_u64(current_time, start_time) <= preempt_grace_ns));
}
if (i == f->num_runlists) {
err = 0;
}
return err;
}
int nvgpu_runlist_update(struct gk20a *g, struct nvgpu_runlist *rl,

View File

@@ -144,7 +144,7 @@ static u64 nvgpu_nvs_tick(struct gk20a *g)
timeslice = nvs_next->timeslice_ns;
nvgpu_domain_next = nvs_next->priv;
nvgpu_runlist_tick(g, nvgpu_domain_next->rl_domains);
(void)nvgpu_runlist_tick(g, nvgpu_domain_next->rl_domains, 0ULL);
sched->active_domain = nvs_next->priv;
nvgpu_mutex_release(&g->sched_mutex);

View File

@@ -33,7 +33,7 @@ struct nvgpu_runlist;
u32 ga10b_runlist_count_max(struct gk20a *g);
u32 ga10b_runlist_length_max(struct gk20a *g);
void ga10b_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist);
int ga10b_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
int ga10b_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
void ga10b_runlist_write_state(struct gk20a *g, u32 runlists_mask,
u32 runlist_state);
u32 ga10b_get_runlist_aperture(struct gk20a *g, struct nvgpu_runlist *runlist);

View File

@@ -81,25 +81,14 @@ void ga10b_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist)
runlist_submit_length_f(runlist->domain->mem_hw->count));
}
int ga10b_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
int ga10b_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
{
struct nvgpu_timeout timeout;
u32 delay = POLL_DELAY_MIN_US;
int ret;
int ret = 1;
nvgpu_timeout_init_cpu_timer(g, &timeout, nvgpu_get_poll_timeout(g));
ret = -ETIMEDOUT;
do {
if ((nvgpu_runlist_readl(g, runlist, runlist_submit_info_r()) &
if ((nvgpu_runlist_readl(g, runlist, runlist_submit_info_r()) &
runlist_submit_info_pending_true_f()) == 0U) {
ret = 0;
break;
}
nvgpu_usleep_range(delay, delay * 2U);
delay = min_t(u32, delay << 1, POLL_DELAY_MAX_US);
} while (nvgpu_timeout_expired(&timeout) == 0);
ret = 0;
}
return ret;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2011-2022, 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"),
@@ -41,7 +41,7 @@ u32 gk20a_runlist_count_max(struct gk20a *g);
u32 gk20a_runlist_length_max(struct gk20a *g);
void gk20a_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist);
int gk20a_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
int gk20a_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
void gk20a_runlist_write_state(struct gk20a *g, u32 runlists_mask,
u32 runlist_state);

View File

@@ -61,29 +61,13 @@ void gk20a_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist)
nvgpu_spinlock_release(&g->fifo.runlist_submit_lock);
}
int gk20a_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
int gk20a_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
{
struct nvgpu_timeout timeout;
u32 delay = POLL_DELAY_MIN_US;
int ret = 0;
int ret = 1;
nvgpu_timeout_init_cpu_timer(g, &timeout, nvgpu_get_poll_timeout(g));
ret = -ETIMEDOUT;
do {
if ((nvgpu_readl(g, fifo_eng_runlist_r(runlist->id)) &
fifo_eng_runlist_pending_true_f()) == 0U) {
ret = 0;
break;
}
nvgpu_usleep_range(delay, delay * 2U);
delay = min_t(u32, delay << 1U, POLL_DELAY_MAX_US);
} while (nvgpu_timeout_expired(&timeout) == 0);
if (ret != 0) {
nvgpu_err(g, "runlist wait timeout: runlist id: %u",
runlist->id);
if ((nvgpu_readl(g, fifo_eng_runlist_r(runlist->id)) &
fifo_eng_runlist_pending_true_f()) == 0U) {
ret = 0;
}
return ret;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2018-2022, 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"),
@@ -61,25 +61,14 @@ void tu104_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist)
fifo_runlist_submit_length_f(runlist->domain->mem_hw->count));
}
int tu104_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
int tu104_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist)
{
struct nvgpu_timeout timeout;
u32 delay = POLL_DELAY_MIN_US;
int ret;
int ret = 1;
nvgpu_timeout_init_cpu_timer(g, &timeout, nvgpu_get_poll_timeout(g));
ret = -ETIMEDOUT;
do {
if ((nvgpu_readl(g, fifo_runlist_submit_info_r(runlist->id)) &
fifo_runlist_submit_info_pending_true_f()) == 0U) {
ret = 0;
break;
}
nvgpu_usleep_range(delay, delay * 2U);
delay = min_t(u32, delay << 1, POLL_DELAY_MAX_US);
} while (nvgpu_timeout_expired(&timeout) == 0);
if ((nvgpu_readl(g, fifo_runlist_submit_info_r(runlist->id)) &
fifo_runlist_submit_info_pending_true_f()) == 0U) {
ret = 0;
}
return ret;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2018-2022, 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"),
@@ -30,6 +30,6 @@ struct nvgpu_runlist;
u32 tu104_runlist_count_max(struct gk20a *g);
void tu104_runlist_hw_submit(struct gk20a *g, struct nvgpu_runlist *runlist);
int tu104_runlist_wait_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
int tu104_runlist_check_pending(struct gk20a *g, struct nvgpu_runlist *runlist);
#endif /* NVGPU_RUNLIST_FIFO_TU104_H */

View File

@@ -1,7 +1,7 @@
/*
* GA10B runlist
*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019-2022, 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"),

View File

@@ -1151,7 +1151,7 @@ static const struct gops_runlist ga100_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = ga100_runlist_hw_submit,
.wait_pending = ga10b_runlist_wait_pending,
.check_pending = ga10b_runlist_check_pending,
.write_state = ga10b_runlist_write_state,
.get_runlist_id = ga10b_runlist_get_runlist_id,
.get_engine_id_from_rleng_id = ga10b_runlist_get_engine_id_from_rleng_id,

View File

@@ -1165,7 +1165,7 @@ static const struct gops_runlist ga10b_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = ga10b_runlist_hw_submit,
.wait_pending = ga10b_runlist_wait_pending,
.check_pending = ga10b_runlist_check_pending,
.write_state = ga10b_runlist_write_state,
.get_runlist_id = ga10b_runlist_get_runlist_id,
.get_runlist_aperture = ga10b_get_runlist_aperture,

View File

@@ -710,7 +710,7 @@ static const struct gops_runlist gm20b_ops_runlist = {
.get_tsg_entry = gk20a_runlist_get_tsg_entry,
.get_ch_entry = gk20a_runlist_get_ch_entry,
.hw_submit = gk20a_runlist_hw_submit,
.wait_pending = gk20a_runlist_wait_pending,
.check_pending = gk20a_runlist_check_pending,
.write_state = gk20a_runlist_write_state,
.init_enginfo = nvgpu_runlist_init_enginfo,
.get_tsg_max_timeslice = gk20a_runlist_max_timeslice,

View File

@@ -989,7 +989,7 @@ static const struct gops_runlist gv11b_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = gk20a_runlist_hw_submit,
.wait_pending = gk20a_runlist_wait_pending,
.check_pending = gk20a_runlist_check_pending,
.write_state = gk20a_runlist_write_state,
.init_enginfo = nvgpu_runlist_init_enginfo,
.get_tsg_max_timeslice = gv11b_runlist_max_timeslice,

View File

@@ -1044,7 +1044,7 @@ static const struct gops_runlist tu104_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = tu104_runlist_hw_submit,
.wait_pending = tu104_runlist_wait_pending,
.check_pending = tu104_runlist_check_pending,
.write_state = gk20a_runlist_write_state,
.init_enginfo = nvgpu_runlist_init_enginfo,
.get_tsg_max_timeslice = gv11b_runlist_max_timeslice,

View File

@@ -710,7 +710,7 @@ static const struct gops_runlist vgpu_ga10b_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = NULL,
.wait_pending = NULL,
.check_pending = NULL,
.init_enginfo = nvgpu_runlist_init_enginfo,
.get_max_channels_per_tsg = gv11b_runlist_get_max_channels_per_tsg,
};

View File

@@ -677,7 +677,7 @@ static const struct gops_runlist vgpu_gv11b_ops_runlist = {
.get_tsg_entry = gv11b_runlist_get_tsg_entry,
.get_ch_entry = gv11b_runlist_get_ch_entry,
.hw_submit = NULL,
.wait_pending = NULL,
.check_pending = NULL,
.init_enginfo = nvgpu_runlist_init_enginfo,
.get_tsg_max_timeslice = gv11b_runlist_max_timeslice,
.get_max_channels_per_tsg = gv11b_runlist_get_max_channels_per_tsg,

View File

@@ -93,7 +93,7 @@ struct gops_runlist {
u32 *runlist, u32 timeslice);
void (*get_ch_entry)(struct nvgpu_channel *ch, u32 *runlist);
void (*hw_submit)(struct gk20a *g, struct nvgpu_runlist *runlist);
int (*wait_pending)(struct gk20a *g, struct nvgpu_runlist *runlist);
int (*check_pending)(struct gk20a *g, struct nvgpu_runlist *runlist);
void (*write_state)(struct gk20a *g, u32 runlists_mask,
u32 runlist_state);
int (*reschedule)(struct nvgpu_channel *ch, bool preempt_next);

View File

@@ -198,7 +198,7 @@ struct nvgpu_runlist {
const struct nvgpu_device *rl_dev_list[RLENG_PER_RUNLIST_SIZE];
/** @endcond DOXYGEN_SHOULD_SKIP_THIS */
};
int nvgpu_runlist_wait_pending_legacy(struct gk20a *g, struct nvgpu_runlist *rl);
bool nvgpu_rl_domain_exists(struct gk20a *g, const char *name);
struct nvgpu_runlist_domain *nvgpu_runlist_domain_alloc(struct gk20a *g,
u64 domain_id);
@@ -233,7 +233,20 @@ nvgpu_runlist_domain_from_domains_list(struct nvgpu_list_node *node)
((uintptr_t)node - offsetof(struct nvgpu_runlist_domain, domains_list));
}
void nvgpu_runlist_tick(struct gk20a *g, struct nvgpu_runlist_domain **rl_domain);
/**
* @brief Submit the nvgpu_runlist_domain instance corresponding to a given domain.
*
* Attempts to switch all the rl_domains and wait appropriately. If preempt_grace_ns
* equals 0, the attempt continues infinitely, otherwise it would timeout if the
* total time exceeds preempt_grace_ns.
*
* @param g Global gk20a struct
* @param rl_domain > Actual array of rl domain thats meant to be scheduled.
* @param preempt_grace_ns -> Max Grace Period for Domain switches.
* @return int 0 if domain switch was successful, else -ETIMEDOUT
*/
int nvgpu_runlist_tick(struct gk20a *g, struct nvgpu_runlist_domain **rl_domain,
u64 preempt_grace_ns);
/**
* @brief Rebuild runlist

View File

@@ -28,7 +28,8 @@ gk20a_ramin_alloc_size
gk20a_ramin_base_shift
gk20a_runlist_length_max
gk20a_runlist_hw_submit
gk20a_runlist_wait_pending
nvgpu_runlist_wait_pending_legacy
gk20a_runlist_check_pending
gk20a_runlist_write_state
gk20a_userd_entry_size
gk20a_vm_release_share

View File

@@ -27,7 +27,8 @@ gk20a_ramin_alloc_size
gk20a_ramin_base_shift
gk20a_runlist_length_max
gk20a_runlist_hw_submit
gk20a_runlist_wait_pending
nvgpu_runlist_wait_pending_legacy
gk20a_runlist_check_pending
gk20a_runlist_write_state
gk20a_userd_entry_size
gk20a_vm_release_share

View File

@@ -744,7 +744,7 @@ test_fifo_init_support.init_support=0
test_fifo_remove_support.remove_support=0
test_gk20a_runlist_hw_submit.hw_submit=0
test_gk20a_runlist_length_max.length_max=0
test_gk20a_runlist_wait_pending.wait_pending=0
test_gk20a_runlist_wait_pending.check_pending=0
test_gk20a_runlist_write_state.write_state=0
[nvgpu_runlist_gv11b]

View File

@@ -177,22 +177,22 @@ int test_gk20a_runlist_wait_pending(struct unit_module *m,
/* no wait */
ctx->count = 0;
err = gk20a_runlist_wait_pending(g, runlist);
err = nvgpu_runlist_wait_pending_legacy(g, runlist);
unit_assert(err == 0, goto done);
/* 1 loop */
ctx->count = 1;
err = gk20a_runlist_wait_pending(g, runlist);
err = nvgpu_runlist_wait_pending_legacy(g, runlist);
unit_assert(err == 0, goto done);
/* 2 loops */
ctx->count = 2;
err = gk20a_runlist_wait_pending(g, runlist);
err = nvgpu_runlist_wait_pending_legacy(g, runlist);
unit_assert(err == 0, goto done);
/* timeout */
ctx->count = U32_MAX;
err = gk20a_runlist_wait_pending(g, runlist);
err = nvgpu_runlist_wait_pending_legacy(g, runlist);
unit_assert(err == -ETIMEDOUT, goto done);
ret = UNIT_SUCCESS;
@@ -235,7 +235,7 @@ struct unit_module_test nvgpu_runlist_gk20a_tests[] = {
UNIT_TEST(init_support, test_fifo_init_support, NULL, 0),
UNIT_TEST(length_max, test_gk20a_runlist_length_max, NULL, 0),
UNIT_TEST(hw_submit, test_gk20a_runlist_hw_submit, NULL, 0),
UNIT_TEST(wait_pending, test_gk20a_runlist_wait_pending, NULL, 0),
UNIT_TEST(check_pending, test_gk20a_runlist_wait_pending, NULL, 0),
UNIT_TEST(write_state, test_gk20a_runlist_write_state, NULL, 0),
UNIT_TEST(remove_support, test_fifo_remove_support, NULL, 0),
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019-2022, 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"),
@@ -76,28 +76,28 @@ int test_gk20a_runlist_hw_submit(struct unit_module *m,
/**
* Test specification for: test_gk20a_runlist_wait_pending
*
* Description: Branch coverage for gk20a_runlist_wait_pending
* Description: Branch coverage for nvgpu_runlist_wait_pending_legacy
*
* Test Type: Feature
*
* Targets: gops_runlist.wait_pending, gk20a_runlist_wait_pending
* Targets: gops_runlist.check_pending, nvgpu_runlist_wait_pending_legacy
*
* Input: test_fifo_init_support() run for this GPU
*
* Steps:
* - Check case where runlist is not pending (not wait).
* - Set register to indicate that runlist is NOT pending.
* - Call gk20a_runlist_wait_pending.
* - Call nvgpu_runlist_wait_pending_legacy.
* - Check case where some polling is needed until runlist is not pending:
* - Install register IO callbacks in order to control
* value read from fifo_eng_runlist_r register.
* - Configure callback to clear pending bit after one nvgpu_readl.
* - Call gk20a_runlist_wait_pending.
* - Call nvgpu_runlist_wait_pending_legacy.
* - Configure callback to clear pending bit after two nvgpu_readl.
* - Call gk20a_runlist_wait_pending.
* - Call nvgpu_runlist_wait_pending_legacy.
* - Check case where polling times out:
* - Set register to indicate that runlist is pending.
* - Call gk20a_runlist_wait_pending.
* - Call nvgpu_runlist_wait_pending_legacy.
*
* Output: Returns PASS if all branches gave expected results. FAIL otherwise.
*/