gpu: nvgpu: take power refcount in gk20a_cde_convert()

We have a gk20a_busy() call in gk20a_buffer_convert_gpu_to_cde()
and we again call gk20a_busy() in gk20a_submit_channel_gpfifo()

If gk20a_do_idle() is triggered in between these two calls,
then this leads to a deadlock and results in idle failure

Hence to avoid this take power refcount in a more fine-grained
way i.e. in gk20a_cde_convert() instead of taking in
gk20a_buffer_convert_gpu_to_cde()

Keep gk20a_cde_execute_buffer() out of the gk20a_busy()/
gk20a_idle() pair since we take power refcount in submit path
anyways

Add correct error handling path in gk20a_cde_convert()

Bug 200287073

Change-Id: Iffea2d4c03f42b47dbf05e7fe8fe2994f9c6b37c
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1324329
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
This commit is contained in:
Deepak Nibade
2017-03-14 14:13:35 +05:30
committed by mobile promotions
parent 3c8eef0d0e
commit ce057d784d

View File

@@ -947,12 +947,16 @@ __releases(&cde_app->mutex)
scatterbuffer_byte_offset < compbits_byte_offset) scatterbuffer_byte_offset < compbits_byte_offset)
return -EINVAL; return -EINVAL;
err = gk20a_busy(g->dev);
if (err)
return err;
nvgpu_mutex_acquire(&g->cde_app.mutex); nvgpu_mutex_acquire(&g->cde_app.mutex);
cde_ctx = gk20a_cde_get_context(g); cde_ctx = gk20a_cde_get_context(g);
nvgpu_mutex_release(&g->cde_app.mutex); nvgpu_mutex_release(&g->cde_app.mutex);
if (IS_ERR(cde_ctx)) { if (IS_ERR(cde_ctx)) {
err = PTR_ERR(cde_ctx); err = PTR_ERR(cde_ctx);
goto exit_unlock; goto exit_idle;
} }
/* First, map the buffer to local va */ /* First, map the buffer to local va */
@@ -960,7 +964,7 @@ __releases(&cde_app->mutex)
/* ensure that the compbits buffer has drvdata */ /* ensure that the compbits buffer has drvdata */
err = gk20a_dmabuf_alloc_drvdata(compbits_scatter_buf, g->dev); err = gk20a_dmabuf_alloc_drvdata(compbits_scatter_buf, g->dev);
if (err) if (err)
goto exit_unlock; goto exit_idle;
/* compbits don't start at page aligned offset, so we need to align /* compbits don't start at page aligned offset, so we need to align
the region to be mapped */ the region to be mapped */
@@ -1003,7 +1007,7 @@ __releases(&cde_app->mutex)
if (!map_vaddr) { if (!map_vaddr) {
dma_buf_put(compbits_scatter_buf); dma_buf_put(compbits_scatter_buf);
err = -EINVAL; err = -EINVAL;
goto exit_unlock; goto exit_idle;
} }
if (scatterbuffer_byte_offset && if (scatterbuffer_byte_offset &&
@@ -1017,7 +1021,7 @@ __releases(&cde_app->mutex)
gk20a_warn(g->dev, gk20a_warn(g->dev,
"dma_buf_vmap failed"); "dma_buf_vmap failed");
err = -EINVAL; err = -EINVAL;
goto exit_unlock; goto exit_unmap_vaddr;
} }
scatter_buffer = surface + scatterbuffer_byte_offset; scatter_buffer = surface + scatterbuffer_byte_offset;
@@ -1029,7 +1033,7 @@ __releases(&cde_app->mutex)
gk20a_warn(g->dev, gk20a_warn(g->dev,
"mm_pin failed"); "mm_pin failed");
err = -EINVAL; err = -EINVAL;
goto exit_unlock; goto exit_unmap_surface;
} else { } else {
err = g->ops.cde.populate_scatter_buffer(g, sgt, err = g->ops.cde.populate_scatter_buffer(g, sgt,
compbits_byte_offset, scatter_buffer, compbits_byte_offset, scatter_buffer,
@@ -1039,7 +1043,7 @@ __releases(&cde_app->mutex)
gk20a_mm_unpin(g->dev, compbits_scatter_buf, gk20a_mm_unpin(g->dev, compbits_scatter_buf,
sgt); sgt);
if (err) if (err)
goto exit_unlock; goto exit_unmap_surface;
} }
__cpuc_flush_dcache_area(scatter_buffer, scatterbuffer_size); __cpuc_flush_dcache_area(scatter_buffer, scatterbuffer_size);
@@ -1076,7 +1080,7 @@ __releases(&cde_app->mutex)
if (id < 0 || id >= MAX_CDE_USER_PARAMS) { if (id < 0 || id >= MAX_CDE_USER_PARAMS) {
gk20a_warn(cde_ctx->dev, "cde: unknown user parameter"); gk20a_warn(cde_ctx->dev, "cde: unknown user parameter");
err = -EINVAL; err = -EINVAL;
goto exit_unlock; goto exit_unmap_surface;
} }
cde_ctx->user_param_values[id] = param->value; cde_ctx->user_param_values[id] = param->value;
} }
@@ -1085,7 +1089,7 @@ __releases(&cde_app->mutex)
err = gk20a_cde_patch_params(cde_ctx); err = gk20a_cde_patch_params(cde_ctx);
if (err) { if (err) {
gk20a_warn(cde_ctx->dev, "cde: failed to patch parameters"); gk20a_warn(cde_ctx->dev, "cde: failed to patch parameters");
goto exit_unlock; goto exit_unmap_surface;
} }
gk20a_dbg(gpu_dbg_cde, "cde: buffer=cbc, size=%zu, gpuva=%llx\n", gk20a_dbg(gpu_dbg_cde, "cde: buffer=cbc, size=%zu, gpuva=%llx\n",
@@ -1095,11 +1099,13 @@ __releases(&cde_app->mutex)
gk20a_dbg(gpu_dbg_cde, "cde: buffer=scatterbuffer, size=%llu, gpuva=%llx\n", gk20a_dbg(gpu_dbg_cde, "cde: buffer=scatterbuffer, size=%llu, gpuva=%llx\n",
cde_ctx->scatterbuffer_size, cde_ctx->scatterbuffer_vaddr); cde_ctx->scatterbuffer_size, cde_ctx->scatterbuffer_vaddr);
/* take always the postfence as it is needed for protecting the /* take always the postfence as it is needed for protecting the
* cde context */ * cde context */
flags = __flags | NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_GET; flags = __flags | NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_GET;
/* gk20a_cde_execute_buffer() will grab a power reference of it's own */
gk20a_idle(g->dev);
/* execute the conversion buffer, combined with init first if it's the /* execute the conversion buffer, combined with init first if it's the
* first time */ * first time */
err = gk20a_cde_execute_buffer(cde_ctx, err = gk20a_cde_execute_buffer(cde_ctx,
@@ -1110,16 +1116,21 @@ __releases(&cde_app->mutex)
cde_ctx->init_cmd_executed = true; cde_ctx->init_cmd_executed = true;
exit_unlock:
/* unmap the buffers - channel holds references to them now */ /* unmap the buffers - channel holds references to them now */
if (map_vaddr)
gk20a_vm_unmap(cde_ctx->vm, map_vaddr);
if (surface) if (surface)
dma_buf_vunmap(compbits_scatter_buf, surface); dma_buf_vunmap(compbits_scatter_buf, surface);
gk20a_vm_unmap(cde_ctx->vm, map_vaddr);
return err; return err;
exit_unmap_surface:
if (surface)
dma_buf_vunmap(compbits_scatter_buf, surface);
exit_unmap_vaddr:
gk20a_vm_unmap(cde_ctx->vm, map_vaddr);
exit_idle:
gk20a_idle(g->dev);
return err;
} }
static void gk20a_cde_finished_ctx_cb(struct channel_gk20a *ch, void *data) static void gk20a_cde_finished_ctx_cb(struct channel_gk20a *ch, void *data)
@@ -1511,10 +1522,6 @@ static int gk20a_buffer_convert_gpu_to_cde(
if (!g->cde_app.initialised) if (!g->cde_app.initialised)
return -ENOSYS; return -ENOSYS;
err = gk20a_busy(g->dev);
if (err)
return err;
gk20a_dbg(gpu_dbg_cde, "firmware version = %d\n", gk20a_dbg(gpu_dbg_cde, "firmware version = %d\n",
g->cde_app.firmware_version); g->cde_app.firmware_version);
@@ -1530,7 +1537,6 @@ static int gk20a_buffer_convert_gpu_to_cde(
err = -EINVAL; err = -EINVAL;
} }
gk20a_idle(g->dev);
return err; return err;
} }