diff --git a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c index a80d9dd2..862a95ac 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c +++ b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c @@ -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: diff --git a/drivers/video/tegra/host/nvdla/nvdla_queue.c b/drivers/video/tegra/host/nvdla/nvdla_queue.c index 36399857..ae229c7b 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_queue.c +++ b/drivers/video/tegra/host/nvdla/nvdla_queue.c @@ -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;