video: tegra: host: expect more than one postfence

- postfence completion routine triggers clean up of task data and
  inform UMD of completion of task, so expect minimum one postfence
  for task submit.
- add more debug message.
- validate task data after copying user data
- use local task pointer for copying postfences
- dump input task parameters

Jira DLA-251
Bug 200088648

Change-Id: I3980e095586112d50381057aa7e19991d77fdf32
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: http://git-master/r/1311386
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Shridhar Rasal
2017-02-25 10:18:53 +05:30
committed by Laxman Dewangan
parent d1587acdc0
commit 94b372e4e0
3 changed files with 167 additions and 23 deletions

View File

@@ -306,7 +306,7 @@ int nvdla_fill_task_desc(struct nvdla_task *task);
* This function send post fences back to UMD after task submit
*/
int nvdla_send_postfences(struct nvdla_task *task,
struct nvdla_ioctl_submit_task usr_task);
struct nvdla_ioctl_submit_task *usr_task);
int nvdla_get_cmd_memory(struct platform_device *pdev,
struct nvdla_cmd_mem_info *cmd_mem_info);

View File

@@ -59,6 +59,8 @@ static int nvdla_set_queue(struct nvdla_private *priv, void *args)
int status = queue_arg->status;
int err = 0;
nvdla_dbg_fn(pdev, "");
if (!queue) {
nvdla_dbg_err(pdev, "invalid queue\n");
err = -EINVAL;
@@ -81,6 +83,7 @@ static int nvdla_set_queue(struct nvdla_private *priv, void *args)
err = -EINVAL;
goto inval_cmd;
}
nvdla_dbg_fn(pdev, "done");
inval_queue:
inval_input:
@@ -97,6 +100,8 @@ static int nvdla_pin(struct nvdla_private *priv, void *arg)
u32 count;
struct platform_device *pdev = priv->pdev;
nvdla_dbg_fn(pdev, "");
if (!buf_list) {
nvdla_dbg_err(pdev, "Invalid argument ptr in pin\n");
err = -EINVAL;
@@ -119,6 +124,9 @@ static int nvdla_pin(struct nvdla_private *priv, void *arg)
}
err = nvhost_buffer_pin(priv->buffers, handles, count);
if (err)
nvdla_dbg_err(pdev, "failed to pin handles\n");
nvdla_buffer_cpy_err:
fail_to_get_val_cnt:
@@ -135,6 +143,8 @@ static int nvdla_unpin(struct nvdla_private *priv, void *arg)
u32 count;
struct platform_device *pdev = priv->pdev;
nvdla_dbg_fn(pdev, "");
if (!buf_list) {
nvdla_dbg_err(pdev, "Invalid argument for pointer\n");
err = -EINVAL;
@@ -284,14 +294,14 @@ fail:
}
int nvdla_send_postfences(struct nvdla_task *task,
struct nvdla_ioctl_submit_task user_task)
struct nvdla_ioctl_submit_task *user_task)
{
int err = 0, i;
struct platform_device *dla_pdev = task->queue->pool->pdev;
struct platform_device *host_pdev =
to_platform_device(dla_pdev->dev.parent);
struct nvdla_fence __user *postfences =
(struct nvdla_fence __user *)(uintptr_t)user_task.postfences;
(struct nvdla_fence __user *)(uintptr_t)user_task->postfences;
char fence_name[32];
nvdla_dbg_fn(dla_pdev, "sending post fences");
@@ -324,6 +334,7 @@ int nvdla_send_postfences(struct nvdla_task *task,
}
}
nvdla_dbg_fn(dla_pdev, "copy postfences to user");
/* send post fences */
if (copy_to_user(postfences, task->postfences,
(task->num_postfences * sizeof(struct nvdla_fence)))) {
@@ -347,16 +358,39 @@ size_t nvdla_get_max_task_size(void)
static int nvdla_val_task_submit_input(struct nvdla_ioctl_submit_task *in_task)
{
if (in_task->num_prefences > MAX_NUM_NVDLA_PREFENCES)
if (in_task->num_prefences > MAX_NUM_NVDLA_PREFENCES) {
pr_err("num_prefences[%u] crossing expected[%d]\n",
in_task->num_prefences, MAX_NUM_NVDLA_PREFENCES);
return -EINVAL;
if (in_task->num_postfences > MAX_NUM_NVDLA_POSTFENCES)
}
if (in_task->num_postfences < 1) {
pr_err("num postfences[%u] should be min one",
in_task->num_postfences);
return -EINVAL;
if (in_task->num_input_task_status > MAX_NUM_NVDLA_IN_TASK_STATUS)
}
if (in_task->num_postfences > MAX_NUM_NVDLA_POSTFENCES) {
pr_err("num_postfences[%u] crossing expected[%d]\n",
in_task->num_postfences, MAX_NUM_NVDLA_POSTFENCES);
return -EINVAL;
if (in_task->num_output_task_status > MAX_NUM_NVDLA_OUT_TASK_STATUS)
}
if (in_task->num_input_task_status > MAX_NUM_NVDLA_IN_TASK_STATUS) {
pr_err("in task status[%u] crossing expected[%d]\n",
in_task->num_input_task_status,
MAX_NUM_NVDLA_IN_TASK_STATUS);
return -EINVAL;
if (in_task->num_addresses > NVDLA_MAX_BUFFERS_PER_TASK)
}
if (in_task->num_output_task_status > MAX_NUM_NVDLA_OUT_TASK_STATUS) {
pr_err("out task status[%u] crossing expected[%d]\n",
in_task->num_output_task_status,
MAX_NUM_NVDLA_OUT_TASK_STATUS);
return -EINVAL;
}
if (in_task->num_addresses > NVDLA_MAX_BUFFERS_PER_TASK) {
pr_err("num addresses[%u] crossing expected[%d]\n",
in_task->num_addresses,
NVDLA_MAX_BUFFERS_PER_TASK);
return -EINVAL;
}
return 0;
}
@@ -378,6 +412,12 @@ static int nvdla_fill_task(struct nvhost_queue *queue,
task->buffers = buffers;
task->sp = &nvhost_get_host(pdev)->syncpt;
err = nvdla_val_task_submit_input(local_task);
if (err) {
nvdla_dbg_err(pdev, "Invalid input arguments");
goto fail_to_get_val_args;
}
task->num_prefences = local_task->num_prefences;
task->num_postfences = local_task->num_postfences;
task->num_in_task_status = local_task->num_input_task_status;
@@ -420,9 +460,73 @@ static int nvdla_fill_task(struct nvhost_queue *queue,
fail_to_get_addr_list:
fail_to_get_actions:
fail_to_get_val_args:
return err;
}
void nvdla_dump_task(struct nvdla_task *task)
{
int i;
struct nvhost_queue *queue = task->queue;
struct platform_device *pdev = queue->pool->pdev;
nvdla_dbg_info(pdev, "dumping input task [%p] parameters:", task);
nvdla_dbg_info(pdev, "num_prefences[%u] num_postfences[%u]",
task->num_postfences, task->num_postfences);
nvdla_dbg_info(pdev, "num_in_status[%u] num_out_task_status[%u]",
task->num_in_task_status, task->num_out_task_status);
nvdla_dbg_info(pdev, "num_addresses[%u]", task->num_addresses);
for (i = 0; i < task->num_prefences; i++) {
nvdla_dbg_info(pdev, "prefence[%d]: type[%u] syncpt_index[%u]"
" syncpt_val[%u] sync_fd[%u] sem_handle[%u]"
" sem_offset[%u] sem_val[%u]",
i, task->prefences[i].type,
task->prefences[i].syncpoint_index,
task->prefences[i].syncpoint_value,
task->prefences[i].sync_fd,
task->prefences[i].sem_handle,
task->prefences[i].sem_offset,
task->prefences[i].sem_val);
}
for (i = 0; i < task->num_postfences; i++) {
nvdla_dbg_info(pdev, "postfence[%d]: type[%u] syncpt_index[%u]"
" syncpt_val[%u] sync_fd[%u] sem_handle[%u]"
" sem_offset[%u] sem_val[%u]",
i, task->postfences[i].type,
task->postfences[i].syncpoint_index,
task->postfences[i].syncpoint_value,
task->postfences[i].sync_fd,
task->postfences[i].sem_handle,
task->postfences[i].sem_offset,
task->postfences[i].sem_val);
}
for (i = 0; i < task->num_in_task_status; i++) {
nvdla_dbg_info(pdev, "Input task status[%d]:"
"handle[%u] offset[%u] status[%u]",
i, task->in_task_status[i].handle,
task->in_task_status[i].offset,
task->in_task_status[i].status);
}
for (i = 0; i < task->num_out_task_status; i++) {
nvdla_dbg_info(pdev, "Output task status[%d]:"
"handle[%u] offset[%u] status[%u]",
i, task->out_task_status[i].handle,
task->out_task_status[i].offset,
task->out_task_status[i].status);
}
for (i = 0; i < task->num_addresses; i++) {
nvdla_dbg_info(pdev, "Memory Handles[%d]:"
"handle[%u] offset[%u]",
i, task->memory_handles[i].handle,
task->memory_handles[i].offset);
}
}
static int nvdla_submit(struct nvdla_private *priv, void *arg)
{
struct nvdla_submit_args *args =
@@ -441,10 +545,11 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
pdev = priv->pdev;
queue = priv->queue;
if (!queue)
buffers = priv->buffers;
if (!(queue && pdev && buffers))
return -EINVAL;
buffers = priv->buffers;
nvdla_dbg_fn(pdev, "inside task submit");
user_tasks = (struct nvdla_ioctl_submit_task __user *)
(uintptr_t)args->tasks;
@@ -457,20 +562,13 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_info(pdev, "num of tasks [%d]", num_tasks);
for (i = 0; i < num_tasks; i++) {
err = nvdla_val_task_submit_input(user_tasks + i);
if (err) {
nvdla_dbg_err(pdev, "Invalid input arguments");
goto fail_to_val_args;
}
}
/* IOCTL copy descriptors*/
if (copy_from_user(local_tasks, user_tasks,
if (copy_from_user(local_tasks, (void __user *)user_tasks,
(num_tasks * sizeof(*user_tasks)))) {
err = -EFAULT;
goto fail_to_copy_task;
}
nvdla_dbg_info(pdev, "copy of user tasks done");
for (i = 0; i < num_tasks; i++) {
@@ -481,6 +579,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_err(pdev, "failed to get task[%d] mem", i + 1);
goto fail_to_get_task_mem;
}
nvdla_dbg_info(pdev, "task[%d] mem allocate done", i + 1);
/* fill local task param from user args */
err = nvdla_fill_task(queue, buffers, local_tasks + i, task);
@@ -488,6 +587,11 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_err(pdev, "failed to fill task[%d]", i + 1);
goto fail_to_fill_task;
}
nvdla_dbg_info(pdev, "local task[%d] filled", i + 1);
/* dump task input parameters */
nvdla_dump_task(task);
nvdla_dbg_info(pdev, "dump task[%d] done", i + 1);
/* update task desc fields */
err = nvdla_fill_task_desc(task);
@@ -495,6 +599,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_err(pdev, "fail to fill task desc%d", i + 1);
goto fail_to_fill_task_desc;
}
nvdla_dbg_info(pdev, "task[%d] desc filled", i + 1);
/* send job to engine through queue framework */
err = nvhost_queue_submit(queue, task);
@@ -502,14 +607,18 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg)
nvdla_dbg_err(pdev, "fail to submit task: %d", i + 1);
goto fail_to_submit_task;
}
nvdla_dbg_info(pdev, "task[%d] submitted", i + 1);
/* send fences to user */
err = nvdla_send_postfences(task, user_tasks[i]);
err = nvdla_send_postfences(task, local_tasks + i);
if (err) {
nvdla_dbg_err(pdev, "fail to send postfence%d", i + 1);
goto fail_to_send_postfences;
}
nvdla_dbg_info(pdev, "postfences of task[%d] sent", i + 1);
}
nvdla_dbg_fn(pdev, "Task submitted, done!");
return 0;
fail_to_send_postfences:
@@ -519,7 +628,6 @@ fail_to_fill_task:
/*TODO: traverse list in reverse and delete jobs */
fail_to_get_task_mem:
fail_to_copy_task:
fail_to_val_args:
return err;
}
@@ -567,6 +675,7 @@ static long nvdla_ioctl(struct file *file, unsigned int cmd,
err = nvdla_set_queue(priv, (void *)buf);
break;
default:
nvdla_dbg_err(pdev, "invalid IOCTL CMD");
err = -ENOIOCTLCMD;
break;
}

View File

@@ -51,6 +51,9 @@ int nvdla_get_task_mem(struct nvhost_queue *queue,
int err;
struct nvdla_task *task = NULL;
struct nvhost_queue_task_mem_info task_mem_info;
struct platform_device *pdev = queue->pool->pdev;
nvdla_dbg_fn(pdev, "");
/* get mem task descriptor and task mem from task_mem_pool */
err = nvhost_queue_alloc_task_memory(queue, &task_mem_info);
@@ -96,6 +99,9 @@ static void task_free(struct kref *ref)
void nvdla_task_put(struct nvdla_task *task)
{
struct nvhost_queue *queue = task->queue;
struct platform_device *pdev = queue->pool->pdev;
nvdla_dbg_fn(pdev, "task:[%p]", task);
kref_put(&task->ref, task_free);
@@ -105,6 +111,11 @@ void nvdla_task_put(struct nvdla_task *task)
void nvdla_task_get(struct nvdla_task *task)
{
struct nvhost_queue *queue = task->queue;
struct platform_device *pdev = queue->pool->pdev;
nvdla_dbg_fn(pdev, "task:[%p]", task);
/* update queue refcnt */
nvhost_queue_get(task->queue);
@@ -114,6 +125,10 @@ void nvdla_task_get(struct nvdla_task *task)
static int nvdla_unmap_task_memory(struct nvdla_task *task)
{
int ii;
struct nvhost_queue *queue = task->queue;
struct platform_device *pdev = queue->pool->pdev;
nvdla_dbg_fn(pdev, "task:[%p]", task);
/* unpin address list */
for (ii = 0; ii < task->num_addresses; ii++) {
@@ -121,6 +136,7 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task)
nvhost_buffer_submit_unpin(task->buffers,
&task->memory_handles[ii].handle, 1);
}
nvdla_dbg_fn(pdev, "all mem handles unmaped");
/* unpin prefences memory */
for (ii = 0; ii < task->num_prefences; ii++) {
@@ -130,6 +146,7 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task)
&task->prefences[ii].sem_handle, 1);
}
}
nvdla_dbg_fn(pdev, "all prefences unmaped");
/* unpin input task status memory */
for (ii = 0; ii < task->num_in_task_status; ii++) {
@@ -137,6 +154,7 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task)
nvhost_buffer_submit_unpin(task->buffers,
&task->in_task_status[ii].handle, 1);
}
nvdla_dbg_fn(pdev, "all in task status unmaped");
/* unpin postfences memory */
for (ii = 0; ii < task->num_postfences; ii++) {
@@ -147,6 +165,7 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task)
&task->postfences[ii].sem_handle, 1);
}
}
nvdla_dbg_fn(pdev, "all postfences unmaped");
/* unpin input task status memory */
for (ii = 0; ii < task->num_out_task_status; ii++) {
@@ -154,6 +173,7 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task)
nvhost_buffer_submit_unpin(task->buffers,
&task->out_task_status[ii].handle, 1);
}
nvdla_dbg_fn(pdev, "all out task status unmaped");
return 0;
}
@@ -197,6 +217,8 @@ static void nvdla_queue_update(void *priv, int nr_completed)
mutex_lock(&queue->list_lock);
nvdla_dbg_fn(pdev, "");
/* check which task(s) finished */
list_for_each_entry_safe(task, safe, &queue->tasklist, list) {
@@ -204,8 +226,11 @@ static void nvdla_queue_update(void *priv, int nr_completed)
queue->syncpt_id, task->fence);
/* clean task and remove from list */
if (task_complete)
if (task_complete) {
nvdla_dbg_fn(pdev, "task with syncpt[%d] val[%d] done",
queue->syncpt_id, task->fence);
nvdla_task_free_locked(task);
}
}
/* put pm refcount */
nvhost_module_idle_mult(pdev, nr_completed);
@@ -325,6 +350,7 @@ static int nvdla_map_task_memory(struct nvdla_task *task)
sizeof(struct dla_action_list) + nvdla_get_max_preaction_size() +
sizeof(struct dla_action_list) + nvdla_get_max_postaction_size();
offset = roundup(offset, 8);
nvdla_dbg_fn(pdev, "addresslist offset is[%zu]", offset);
/* get task desc address list to update list from kernel */
next = (u8 *)task_desc + offset;
@@ -684,6 +710,10 @@ int nvdla_fill_task_desc(struct nvdla_task *task)
task_desc->queue_id = queue->id;
nvdla_dbg_info(pdev, "Queue id[%d]", task_desc->queue_id);
nvdla_dbg_info(pdev, "version[%d]", task_desc->version);
nvdla_dbg_info(pdev, "engine_id[%d]", task_desc->engine_id);
nvdla_dbg_info(pdev, "task desc size[%u]", task_desc->size);
nvdla_dbg_info(pdev, "task desc sequence[%u]", task_desc->sequence);
/* get pre/post action list HEAD mem offset
* - preactions list HEAD stored after dla_task_descriptor
@@ -742,6 +772,9 @@ static int nvdla_queue_submit(struct nvhost_queue *queue, void *in_task)
last_task = list_last_entry(&queue->tasklist,
struct nvdla_task, list);
last_task->task_desc->next = (uint64_t)task->task_desc_pa;
nvdla_dbg_info(pdev, "last task[%p] last_task_desc_pa[%llu]",
last_task, task->task_desc_pa);
}
list_add_tail(&task->list, &queue->tasklist);
@@ -779,9 +812,11 @@ static int nvdla_queue_submit(struct nvhost_queue *queue, void *in_task)
/* submit task to engine */
err = nvdla_send_cmd(pdev, &cmd_data);
if (err)
if (err) {
nvdla_task_syncpt_reset(task->sp, queue->syncpt_id,
task->fence);
nvdla_dbg_err(pdev, "task[%p] submit failed", task);
}
fail_to_register:
mutex_unlock(&queue->list_lock);