diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index c2a21b22f..407668579 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -910,10 +910,8 @@ static void gk20a_wait_until_counter_is_N( } } - - /* call ONLY when no references to the channel exist: after the last put */ -static void gk20a_free_channel(struct channel_gk20a *ch) +static void gk20a_free_channel(struct channel_gk20a *ch, bool force) { struct gk20a *g = ch->g; struct fifo_gk20a *f = &g->fifo; @@ -935,9 +933,10 @@ static void gk20a_free_channel(struct channel_gk20a *ch) gk20a_disable_channel(ch); /* wait until there's only our ref to the channel */ - gk20a_wait_until_counter_is_N( - ch, &ch->ref_count, 1, &ch->ref_count_dec_wq, - __func__, "references"); + if (!force) + gk20a_wait_until_counter_is_N( + ch, &ch->ref_count, 1, &ch->ref_count_dec_wq, + __func__, "references"); /* wait until all pending interrupts for recently completed * jobs are handled */ @@ -959,9 +958,10 @@ static void gk20a_free_channel(struct channel_gk20a *ch) atomic_dec(&ch->ref_count); /* wait until no more refs to the channel */ - gk20a_wait_until_counter_is_N( - ch, &ch->ref_count, 0, &ch->ref_count_dec_wq, - __func__, "references"); + if (!force) + gk20a_wait_until_counter_is_N( + ch, &ch->ref_count, 0, &ch->ref_count_dec_wq, + __func__, "references"); /* if engine reset was deferred, perform it now */ mutex_lock(&f->deferred_reset_mutex); @@ -1132,7 +1132,17 @@ void _gk20a_channel_put(struct channel_gk20a *ch, const char *caller) void gk20a_channel_close(struct channel_gk20a *ch) { - gk20a_free_channel(ch); + gk20a_free_channel(ch, false); +} + +/* + * Be careful with this - it is meant for terminating channels when we know the + * driver is otherwise dying. Ref counts and the like are ignored by this + * version of the cleanup. + */ +void __gk20a_channel_kill(struct channel_gk20a *ch) +{ + gk20a_free_channel(ch, true); } struct channel_gk20a *gk20a_get_channel_from_file(int fd) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index 0ad1bbaa2..ba9f332d9 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h @@ -226,6 +226,7 @@ int gk20a_init_channel_support(struct gk20a *, u32 chid); /* must be inside gk20a_busy()..gk20a_idle() */ void gk20a_channel_close(struct channel_gk20a *ch); +void __gk20a_channel_kill(struct channel_gk20a *ch); bool gk20a_channel_update_and_check_timeout(struct channel_gk20a *ch, u32 timeout_delta_ms, bool *progress);