gpu: nvgpu: Support semaphore sync when aborting jobs

When aborting jobs on channel error situations, we manually set
the channel syncpoint's min == max in gk20a_disable_channel_no_update.
Nvhost will notice this manual syncpoint increment, and will call back
to gk20a_channel_update, which will clean up the job.

With semaphore synchronization, we don't have anybody calling back to
gk20a_channel_update, so we need to call it ourselves. Release job
semaphores (the equivalent of set_min_eq_max) on
gk20a_disable_channel_no_update, and if any semaphores were released,
call gk20a_channel_update afterwards.

Because we are actually calling gk20a_channel_update in some situations,
gk20a_disable_channel_no_update is no longer an appropriate name for the
function. Rename it to gk20a_channel_abort.

Bug 1450122

Change-Id: I1267b099a5778041cbc8e91b7184844812145b93
Signed-off-by: Lauri Peltonen <lpeltonen@nvidia.com>
Reviewed-on: http://git-master/r/422161
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Lauri Peltonen
2014-06-11 12:56:31 +03:00
committed by Dan Willemsen
parent ae22cda010
commit f575bc6676
3 changed files with 24 additions and 5 deletions

View File

@@ -406,17 +406,36 @@ static int channel_gk20a_update_runlist(struct channel_gk20a *c, bool add)
return gk20a_fifo_update_runlist(c->g, 0, c->hw_chid, add, true); return gk20a_fifo_update_runlist(c->g, 0, c->hw_chid, add, true);
} }
void gk20a_disable_channel_no_update(struct channel_gk20a *ch) void gk20a_channel_abort(struct channel_gk20a *ch)
{ {
struct channel_gk20a_job *job, *n;
bool released_job_semaphore = false;
/* ensure no fences are pending */ /* ensure no fences are pending */
if (ch->sync) if (ch->sync)
ch->sync->set_min_eq_max(ch->sync); ch->sync->set_min_eq_max(ch->sync);
/* release all job semaphores (applies only to jobs that use
semaphore synchronization) */
mutex_lock(&ch->jobs_lock);
list_for_each_entry_safe(job, n, &ch->jobs, list) {
if (job->post_fence.semaphore) {
gk20a_semaphore_release(job->post_fence.semaphore);
released_job_semaphore = true;
}
}
mutex_unlock(&ch->jobs_lock);
/* disable channel */ /* disable channel */
gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid), gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid),
gk20a_readl(ch->g, gk20a_readl(ch->g,
ccsr_channel_r(ch->hw_chid)) | ccsr_channel_r(ch->hw_chid)) |
ccsr_channel_enable_clr_true_f()); ccsr_channel_enable_clr_true_f());
if (released_job_semaphore) {
wake_up_interruptible_all(&ch->semaphore_wq);
gk20a_channel_update(ch, 0);
}
} }
int gk20a_wait_channel_idle(struct channel_gk20a *ch) int gk20a_wait_channel_idle(struct channel_gk20a *ch)
@@ -455,7 +474,7 @@ void gk20a_disable_channel(struct channel_gk20a *ch,
} }
/* disable the channel from hw and increment syncpoints */ /* disable the channel from hw and increment syncpoints */
gk20a_disable_channel_no_update(ch); gk20a_channel_abort(ch);
gk20a_wait_channel_idle(ch); gk20a_wait_channel_idle(ch);

View File

@@ -153,7 +153,7 @@ bool gk20a_channel_update_and_check_timeout(struct channel_gk20a *ch,
void gk20a_disable_channel(struct channel_gk20a *ch, void gk20a_disable_channel(struct channel_gk20a *ch,
bool wait_for_finish, bool wait_for_finish,
unsigned long finish_timeout); unsigned long finish_timeout);
void gk20a_disable_channel_no_update(struct channel_gk20a *ch); void gk20a_channel_abort(struct channel_gk20a *ch);
int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout); int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout);
void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error); void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error);
void gk20a_channel_semaphore_wakeup(struct gk20a *g); void gk20a_channel_semaphore_wakeup(struct gk20a *g);

View File

@@ -1043,7 +1043,7 @@ static bool gk20a_fifo_handle_mmu_fault(struct gk20a *g)
if (ch->in_use) { if (ch->in_use) {
/* disable the channel from hw and increment /* disable the channel from hw and increment
* syncpoints */ * syncpoints */
gk20a_disable_channel_no_update(ch); gk20a_channel_abort(ch);
/* remove the channel from runlist */ /* remove the channel from runlist */
clear_bit(ch->hw_chid, clear_bit(ch->hw_chid,
@@ -1180,7 +1180,7 @@ void gk20a_fifo_recover_ch(struct gk20a *g, u32 hw_chid, bool verbose)
struct channel_gk20a *ch = struct channel_gk20a *ch =
g->fifo.channel + hw_chid; g->fifo.channel + hw_chid;
gk20a_disable_channel_no_update(ch); gk20a_channel_abort(ch);
for (i = 0; i < g->fifo.max_runlists; i++) for (i = 0; i < g->fifo.max_runlists; i++)
gk20a_fifo_update_runlist(g, i, gk20a_fifo_update_runlist(g, i,
hw_chid, false, false); hw_chid, false, false);