gpu: nvgpu: Allow semaphores to be force released

Allow SW to force a semaphore release. Typically SW waits for a
semaphore to reach the value right before the semaphore release
value before doing a release. For example, assuming a semaphore
is to be released by SW by writing a 10 into the semaphore, the
code waits for the semaphore to get to 9 before writing 10.

The problem with this happens when trying to shutdown the GPU
unexpectedly. When aborting a channel after the GPU has terminated
the GPU is potantially no longer processing anything. If a SW
semaphore release is waiting on the semaphore to reach N-1 before
writing N to the semaphore N-1 may never get written by the GPU.
This obviously causes a hang in the SW shutdown. The solution is
to let SW force a semaphore release in the channel_abort case.

Bug 1816516
Bug 1807277

Change-Id: Ib8b4afd86102eacf372362b1748fb6ca04e6fa66
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/1250021
(cherry picked from commit 2e9fa40902d2c4d5a1febe0bf2db420ce14bc633)
Reviewed-on: http://git-master/r/1261915
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Alex Waterman
2016-11-07 15:25:34 -08:00
committed by mobile promotions
parent da0f793f77
commit 274e1881af
2 changed files with 15 additions and 6 deletions

View File

@@ -514,8 +514,8 @@ void gk20a_channel_abort_clean_up(struct channel_gk20a *ch)
while (tmp_get != put) {
job = &ch->joblist.pre_alloc.jobs[tmp_get];
if (job->post_fence->semaphore) {
gk20a_semaphore_release(
job->post_fence->semaphore);
__gk20a_semaphore_release(
job->post_fence->semaphore, true);
released_job_semaphore = true;
}
tmp_get = (tmp_get + 1) % ch->joblist.pre_alloc.length;
@@ -524,8 +524,8 @@ void gk20a_channel_abort_clean_up(struct channel_gk20a *ch)
list_for_each_entry_safe(job, n,
&ch->joblist.dynamic.jobs, list) {
if (job->post_fence->semaphore) {
gk20a_semaphore_release(
job->post_fence->semaphore);
__gk20a_semaphore_release(
job->post_fence->semaphore, true);
released_job_semaphore = true;
}
}

View File

@@ -249,9 +249,11 @@ static inline u32 gk20a_semaphore_next_value(struct gk20a_semaphore *s)
}
/*
* Note - if you call this then any prior semaphores will also be released.
* If @force is set then this will not wait for the underlying semaphore to
* catch up to the passed semaphore.
*/
static inline void gk20a_semaphore_release(struct gk20a_semaphore *s)
static inline void __gk20a_semaphore_release(struct gk20a_semaphore *s,
bool force)
{
u32 current_val;
u32 val = gk20a_semaphore_get_value(s);
@@ -264,6 +266,8 @@ static inline void gk20a_semaphore_release(struct gk20a_semaphore *s)
* TODO: tune the wait a little better.
*/
while ((current_val = gk20a_semaphore_read(s)) < (val - 1)) {
if (force)
break;
msleep(100);
attempts += 1;
if (attempts > 100) {
@@ -285,6 +289,11 @@ static inline void gk20a_semaphore_release(struct gk20a_semaphore *s)
s->hw_sema->ch->hw_chid, val);
}
static inline void gk20a_semaphore_release(struct gk20a_semaphore *s)
{
__gk20a_semaphore_release(s, false);
}
/*
* Configure a software based increment on this semaphore. This is useful for
* when we want the GPU to wait on a SW event before processing a channel.