diff options
author | Alex Waterman <alexw@nvidia.com> | 2016-11-07 18:25:34 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2016-12-19 18:40:03 -0500 |
commit | 274e1881af2e4c327fda5e28eb804fe304a2f36e (patch) | |
tree | 6c50ffc463211ebaaffefb908467692bcafdcce2 /drivers/gpu | |
parent | da0f793f77944cadc89918723ff578652127f27c (diff) |
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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 8 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h | 13 |
2 files changed, 15 insertions, 6 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index f9b29396..c2a21b22 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -514,8 +514,8 @@ void gk20a_channel_abort_clean_up(struct channel_gk20a *ch) | |||
514 | while (tmp_get != put) { | 514 | while (tmp_get != put) { |
515 | job = &ch->joblist.pre_alloc.jobs[tmp_get]; | 515 | job = &ch->joblist.pre_alloc.jobs[tmp_get]; |
516 | if (job->post_fence->semaphore) { | 516 | if (job->post_fence->semaphore) { |
517 | gk20a_semaphore_release( | 517 | __gk20a_semaphore_release( |
518 | job->post_fence->semaphore); | 518 | job->post_fence->semaphore, true); |
519 | released_job_semaphore = true; | 519 | released_job_semaphore = true; |
520 | } | 520 | } |
521 | tmp_get = (tmp_get + 1) % ch->joblist.pre_alloc.length; | 521 | tmp_get = (tmp_get + 1) % ch->joblist.pre_alloc.length; |
@@ -524,8 +524,8 @@ void gk20a_channel_abort_clean_up(struct channel_gk20a *ch) | |||
524 | list_for_each_entry_safe(job, n, | 524 | list_for_each_entry_safe(job, n, |
525 | &ch->joblist.dynamic.jobs, list) { | 525 | &ch->joblist.dynamic.jobs, list) { |
526 | if (job->post_fence->semaphore) { | 526 | if (job->post_fence->semaphore) { |
527 | gk20a_semaphore_release( | 527 | __gk20a_semaphore_release( |
528 | job->post_fence->semaphore); | 528 | job->post_fence->semaphore, true); |
529 | released_job_semaphore = true; | 529 | released_job_semaphore = true; |
530 | } | 530 | } |
531 | } | 531 | } |
diff --git a/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h index c73d3c05..cf724fdb 100644 --- a/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/semaphore_gk20a.h | |||
@@ -249,9 +249,11 @@ static inline u32 gk20a_semaphore_next_value(struct gk20a_semaphore *s) | |||
249 | } | 249 | } |
250 | 250 | ||
251 | /* | 251 | /* |
252 | * Note - if you call this then any prior semaphores will also be released. | 252 | * If @force is set then this will not wait for the underlying semaphore to |
253 | * catch up to the passed semaphore. | ||
253 | */ | 254 | */ |
254 | static inline void gk20a_semaphore_release(struct gk20a_semaphore *s) | 255 | static inline void __gk20a_semaphore_release(struct gk20a_semaphore *s, |
256 | bool force) | ||
255 | { | 257 | { |
256 | u32 current_val; | 258 | u32 current_val; |
257 | u32 val = gk20a_semaphore_get_value(s); | 259 | u32 val = gk20a_semaphore_get_value(s); |
@@ -264,6 +266,8 @@ static inline void gk20a_semaphore_release(struct gk20a_semaphore *s) | |||
264 | * TODO: tune the wait a little better. | 266 | * TODO: tune the wait a little better. |
265 | */ | 267 | */ |
266 | while ((current_val = gk20a_semaphore_read(s)) < (val - 1)) { | 268 | while ((current_val = gk20a_semaphore_read(s)) < (val - 1)) { |
269 | if (force) | ||
270 | break; | ||
267 | msleep(100); | 271 | msleep(100); |
268 | attempts += 1; | 272 | attempts += 1; |
269 | if (attempts > 100) { | 273 | if (attempts > 100) { |
@@ -285,6 +289,11 @@ static inline void gk20a_semaphore_release(struct gk20a_semaphore *s) | |||
285 | s->hw_sema->ch->hw_chid, val); | 289 | s->hw_sema->ch->hw_chid, val); |
286 | } | 290 | } |
287 | 291 | ||
292 | static inline void gk20a_semaphore_release(struct gk20a_semaphore *s) | ||
293 | { | ||
294 | __gk20a_semaphore_release(s, false); | ||
295 | } | ||
296 | |||
288 | /* | 297 | /* |
289 | * Configure a software based increment on this semaphore. This is useful for | 298 | * Configure a software based increment on this semaphore. This is useful for |
290 | * when we want the GPU to wait on a SW event before processing a channel. | 299 | * when we want the GPU to wait on a SW event before processing a channel. |