nvdla: kmd: cleanup error propagation in submit

[1] Prior to this commit,
    - Errors during nvdla_fill_preactions/postactions are ignored and continued.
    - Resources (task memory, references) are not cleaned up leading to resource
        leak.
[3] This commit fixes the issue by handling resource cleanup and errors
    propagations.

Bug 200680501

Change-Id: I34d96d24e669f79cca09e38ba9ecb0ccb0c7d726
Signed-off-by: Arvind M <am@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2517596
Reviewed-by: Ken Adams <kadams@nvidia.com>
Reviewed-by: Anup Mahindre <amahindre@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Arvind M
2021-04-20 11:12:02 +05:30
committed by Laxman Dewangan
parent 6242fdd281
commit da00f99aa3
2 changed files with 40 additions and 13 deletions

View File

@@ -1,7 +1,7 @@
/*
* NVDLA IOCTL for T194
*
* Copyright (c) 2016-2020, NVIDIA Corporation. All rights reserved.
* Copyright (c) 2016-2021, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -638,6 +638,10 @@ static int nvdla_update_signal_fences(struct nvdla_task *task,
nvdla_dbg_info(dla_pdev, "postfences copied for user");
fail:
/**
* TODO: Unmap task memory in event of failure.
* Defering the fix since this is rare failure to encounter.
**/
return err;
}
@@ -715,7 +719,6 @@ static int nvdla_fill_task(struct nvdla_queue *queue,
nvdla_dbg_fn(pdev, "");
/* initialize task parameters */
kref_init(&task->ref);
task->queue = queue;
task->buffers = buffers;
task->sp = &nvhost_get_host(pdev)->syncpt;
@@ -1024,7 +1027,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
struct nvdla_queue *queue;
struct nvdla_buffers *buffers;
u32 num_tasks;
struct nvdla_task *task;
struct nvdla_task *task = NULL; // task under submission
int err = 0, i = 0;
if (!args || !priv)
@@ -1058,7 +1061,6 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_info(pdev, "copy of user tasks done");
for (i = 0; i < num_tasks; i++) {
nvdla_dbg_info(pdev, "submit [%d]th task", i + 1);
err = nvdla_get_task_mem(queue, &task);
@@ -1068,11 +1070,13 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
}
nvdla_dbg_info(pdev, "task[%d] mem allocate done", i + 1);
/* Initialize ref for task submit preparation */
kref_init(&task->ref);
/* fill local task param from user args */
err = nvdla_fill_task(queue, buffers, local_tasks + i, task);
if (err) {
nvdla_dbg_err(pdev, "failed to fill task[%d]", i + 1);
kref_put(&task->ref, task_free);
goto fail_to_fill_task;
}
nvdla_dbg_info(pdev, "local task[%d] filled", i + 1);
@@ -1118,11 +1122,22 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
return 0;
/**
* Note:
* Any failures during a task submit preparation,
* 1. shall not affect previous tasks within this submit that has been
* successfully submitted.
* 2. shall abandon consecutive tasks within this submit.
**/
fail_to_submit_task:
fail_to_update_postfences:
fail_to_get_fences:
fail_to_fill_task_desc:
fail_to_fill_task:
/* Remove ref corresponding task submit preparation */
if (task != NULL)
kref_put(&task->ref, task_free);
/*TODO: traverse list in reverse and delete jobs */
fail_to_get_task_mem:
fail_to_copy_task:

View File

@@ -1269,14 +1269,22 @@ int nvdla_fill_task_desc(struct nvdla_task *task)
task->fence_counter = 0;
/* fill pre actions */
nvdla_fill_preactions(task);
err = nvdla_fill_preactions(task);
if (err != 0) {
nvdla_dbg_err(pdev, "fail to fill preactions");
goto fail_to_map_mem;
}
/* fill post actions */
nvdla_fill_postactions(task);
err = nvdla_fill_postactions(task);
if (err != 0) {
nvdla_dbg_err(pdev, "fail to fill postactions");
goto fail_to_map_mem;
}
/* ping user memory before submit to engine */
err = nvdla_map_task_memory(task);
if (err) {
if (err != 0) {
nvdla_dbg_err(pdev, "fail to pin mem");
goto fail_to_map_mem;
}
@@ -1286,6 +1294,7 @@ int nvdla_fill_task_desc(struct nvdla_task *task)
return 0;
fail_to_map_mem:
(void) nvdla_unmap_task_memory(task);
return err;
}
@@ -1479,9 +1488,6 @@ int nvdla_get_signal_fences(struct nvdla_queue *queue, void *in_task)
nvdla_dbg_fn(pdev, "");
/* get task ref */
nvdla_task_get(task);
if (task->fence_counter == 0)
task->fence_counter = 1;
@@ -1549,6 +1555,9 @@ static int nvdla_queue_submit_op(struct nvdla_queue *queue, void *in_task)
mutex_lock(&queue->list_lock);
/* Get a reference before registration or submission */
nvdla_task_get(task);
/* get fence from nvhost for MMIO mode*/
if (nvdla_dev->submit_mode == NVDLA_SUBMIT_MODE_MMIO) {
task->fence = nvhost_syncpt_incr_max(task->sp,
@@ -1617,8 +1626,10 @@ static int nvdla_queue_submit_op(struct nvdla_queue *queue, void *in_task)
err = nvdla_send_cmd(pdev, &cmd_data);
if (err) {
nvdla_dbg_err(pdev, "task[%p] submit failed", task);
nvdla_task_syncpt_reset(task->sp, queue->syncpt_id,
task->fence);
/* deletes invalid task from queue, puts refs */
nvdla_task_syncpt_reset(task->sp,
queue->syncpt_id,
task->fence);
}
}
@@ -1645,6 +1656,7 @@ fail_to_register:
fail_to_channel_submit:
nvhost_module_idle(pdev);
fail_to_poweron:
nvdla_task_free_locked(task);
mutex_unlock(&queue->list_lock);
return err;