diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index d656ecee..697447be 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -99,6 +99,8 @@ */ #define MAX_NUM_NVDLA_PREFENCES 32 #define MAX_NUM_NVDLA_POSTFENCES 32 +#define MAX_NUM_NVDLA_EMU_PREFENCES 16 +#define MAX_NUM_NVDLA_EMU_POSTFENCES 16 #define MAX_NUM_NVDLA_IN_TASK_STATUS MAX_NUM_NVDLA_PREFENCES #define MAX_NUM_NVDLA_OUT_TASK_STATUS MAX_NUM_NVDLA_POSTFENCES #define NUM_PROFILING_POSTACTION 1 @@ -219,7 +221,9 @@ struct nvdla_device { * * @queue Queue in which task submitted * @sp pointer to syncpt + * @prefences pointer to pre fences * @postfences pointer to post fences + * @num_prefences Number of prefences in task * @num_postfences Number of postfences in task * @fence Fence tracking for current task * @fence_counter Counter used to track fence value @@ -228,7 +232,9 @@ struct nvdla_device { struct nvdla_emu_task { struct nvdla_queue *queue; struct nvhost_syncpt *sp; - struct nvdev_fence postfences[MAX_NUM_NVDLA_POSTFENCES]; + struct nvdev_fence prefences[MAX_NUM_NVDLA_EMU_PREFENCES]; + struct nvdev_fence postfences[MAX_NUM_NVDLA_EMU_POSTFENCES]; + u32 num_prefences; u32 num_postfences; u32 fence; u32 fence_counter; @@ -402,7 +408,7 @@ int nvdla_free_gcov_region(struct platform_device *pdev, bool update_region); int nvdla_emulator_submit(struct nvdla_queue *queue, struct nvdla_emu_task *task); void task_free(struct kref *ref); -int nvdla_get_postfences(struct nvdla_queue *queue, void *in_task); +int nvdla_get_signal_fences(struct nvdla_queue *queue, void *in_task); int nvdla_send_gos_region(struct platform_device *pdev); #endif /* End of __NVHOST_NVDLA_H__ */ diff --git a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c index 290b1b8c..266a9d27 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c +++ b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c @@ -392,20 +392,66 @@ fail: return err; } -static int nvdla_send_emu_postfences(struct nvdla_emu_task *task, +static int nvdla_send_emu_signal_fences(struct nvdla_emu_task *task, struct nvdla_ioctl_emu_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 nvdev_fence __user *prefences = + (struct nvdev_fence __user *)(uintptr_t)user_task->prefences; struct nvdev_fence __user *postfences = (struct nvdev_fence __user *)(uintptr_t)user_task->postfences; char fence_name[32]; - nvdla_dbg_fn(dla_pdev, "sending post fences"); + nvdla_dbg_fn(dla_pdev, "sending signal fences"); + + for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + if (task->prefences[i].type == NVDEV_FENCE_TYPE_SYNC_FD) { + struct nvhost_ctrl_sync_fence_info info; + + info.id = task->prefences[i].syncpoint_index; + info.thresh = task->prefences[i].syncpoint_value; + + nvdla_dbg_info(dla_pdev, + "creating pre sync fd [%d]:[%d]\n", + info.id, info.thresh); + + /* create fence name format example: nvdla0_1_fence */ + snprintf(fence_name, sizeof(fence_name), + "%s_%d_%d_prefence", dev_name(&dla_pdev->dev), + task->prefences[i].syncpoint_index, i); + + err = nvhost_sync_create_fence_fd(host_pdev, + &info, 1, fence_name, + &task->prefences[i].sync_fd); + + if (err) { + nvdla_dbg_err(dla_pdev, + "fail to create prefence syncfd\n"); + goto fail; + } + } + } + + nvdla_dbg_fn(dla_pdev, "copy prefences to user"); + /* send pre fences */ + if (copy_to_user(prefences, task->prefences, + (task->num_prefences * sizeof(struct nvdev_fence)))) { + err = -EFAULT; + nvdla_dbg_err(dla_pdev, "failed to send prefences"); + goto fail; + } + nvdla_dbg_info(dla_pdev, "prefences sent"); for (i = 0; i < task->num_postfences; i++) { + if (task->postfences[i].action != NVDEV_FENCE_SIGNAL) + continue; + if (task->postfences[i].type == NVDEV_FENCE_TYPE_SYNC_FD) { struct nvhost_ctrl_sync_fence_info info; @@ -418,8 +464,8 @@ static int nvdla_send_emu_postfences(struct nvdla_emu_task *task, /* create fence name format example: nvdla0_1_fence */ snprintf(fence_name, sizeof(fence_name), - "%s_%d_fence", dev_name(&dla_pdev->dev), - task->postfences[i].syncpoint_index); + "%s_%d_%d_postfence", dev_name(&dla_pdev->dev), + task->postfences[i].syncpoint_index, i); err = nvhost_sync_create_fence_fd(host_pdev, &info, 1, fence_name, @@ -447,20 +493,67 @@ fail: return err; } -static int nvdla_update_postfences(struct nvdla_task *task, +static int nvdla_update_signal_fences(struct nvdla_task *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 nvdev_fence __user *prefences = + (struct nvdev_fence __user *)(uintptr_t)user_task->prefences; struct nvdev_fence __user *postfences = (struct nvdev_fence __user *)(uintptr_t)user_task->postfences; char fence_name[32]; - nvdla_dbg_fn(dla_pdev, "copy post fences for user"); + nvdla_dbg_fn(dla_pdev, "copy fences for user"); + /* update pre fence signals to users */ + for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + if (task->prefences[i].type == NVDEV_FENCE_TYPE_SYNC_FD) { + struct nvhost_ctrl_sync_fence_info info; + + info.id = task->prefences[i].syncpoint_index; + info.thresh = task->prefences[i].syncpoint_value; + + nvdla_dbg_info(dla_pdev, + "creating pre sync fd [%d]:[%d]\n", + info.id, info.thresh); + + /* create fence name format example: nvdla0_1_fence */ + snprintf(fence_name, sizeof(fence_name), + "%s_%d_%d_prefence", dev_name(&dla_pdev->dev), + task->prefences[i].syncpoint_index, i); + + err = nvhost_sync_create_fence_fd(host_pdev, + &info, 1, fence_name, + &task->prefences[i].sync_fd); + + if (err) { + nvdla_dbg_err(dla_pdev, + "fail to create prefence syncfd\n"); + goto fail; + } + } + } + + nvdla_dbg_fn(dla_pdev, "copy prefences to user"); + /* copy pre fences */ + if (copy_to_user(prefences, task->prefences, + (task->num_prefences * sizeof(struct nvdev_fence)))) { + err = -EFAULT; + nvdla_dbg_err(dla_pdev, "failed to copy prefences"); + goto fail; + } + + /* update post fence signals to user */ for (i = 0; i < task->num_postfences; i++) { + if (task->postfences[i].action != NVDEV_FENCE_SIGNAL) + continue; + if (task->postfences[i].type == NVDEV_FENCE_TYPE_SYNC_FD) { struct nvhost_ctrl_sync_fence_info info; @@ -473,8 +566,8 @@ static int nvdla_update_postfences(struct nvdla_task *task, /* create fence name format example: nvdla0_1_fence */ snprintf(fence_name, sizeof(fence_name), - "%s_%d_fence", dev_name(&dla_pdev->dev), - task->postfences[i].syncpoint_index); + "%s_%d_%d_postfence", dev_name(&dla_pdev->dev), + task->postfences[i].syncpoint_index, i); err = nvhost_sync_create_fence_fd(host_pdev, &info, 1, fence_name, @@ -531,9 +624,9 @@ static int nvdla_val_task_submit_input(struct nvdla_ioctl_submit_task *in_task) MAX_NUM_NVDLA_OUT_TASK_STATUS); return -EINVAL; } - if (in_task->num_addresses < 1) { + if (in_task->num_addresses < 1) { pr_err("num addresses[%u] should be min one\n", - in_task->num_addresses); + in_task->num_addresses); return -EINVAL; } if (in_task->num_addresses > NVDLA_MAX_BUFFERS_PER_TASK) { @@ -718,8 +811,18 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_info(pdev, "submit [%d]th task", i + 1); + task.num_prefences = local_tasks[i].num_prefences; task.num_postfences = local_tasks[i].num_postfences; + /* get pre fences */ + if (copy_from_user(task.prefences, + (void __user *)local_tasks[i].prefences, + (task.num_prefences * sizeof(struct nvdev_fence)))) { + err = -EFAULT; + nvdla_dbg_err(pdev, "failed to copy prefences"); + goto exit; + } + /* get post fences */ if (copy_from_user(task.postfences, (void __user *)local_tasks[i].postfences, @@ -736,13 +839,13 @@ static int nvdla_emu_task_submit(struct nvdla_private *priv, void *arg) } nvdla_dbg_info(pdev, "task[%d] submitted", i + 1); - /* send fences to user */ - err = nvdla_send_emu_postfences(&task, local_tasks + i); + /* send signal fences to user */ + err = nvdla_send_emu_signal_fences(&task, local_tasks + i); if (err) { - nvdla_dbg_err(pdev, "fail to send postfence%d", i + 1); + nvdla_dbg_err(pdev, "fail to send sig fence%d", i + 1); goto exit; } - nvdla_dbg_info(pdev, "postfences of task[%d] sent", i + 1); + nvdla_dbg_info(pdev, "signal fences of task[%d] sent", i + 1); } nvdla_dbg_fn(pdev, "Emulator task submitted, done!"); @@ -825,8 +928,8 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) } nvdla_dbg_info(pdev, "task[%d] desc filled", i + 1); - /* get expected postfences prior to submit */ - err = nvdla_get_postfences(queue, task); + /* get expected signal fences prior to submit */ + err = nvdla_get_signal_fences(queue, task); if (err) { nvdla_dbg_err(pdev, "fail to get fences%d", i + 1); goto fail_to_get_fences; @@ -834,7 +937,7 @@ static int nvdla_submit(struct nvdla_private *priv, void *arg) nvdla_dbg_info(pdev, "task[%d] got fences", i + 1); /* update fences to user */ - err = nvdla_update_postfences(task, local_tasks + i); + err = nvdla_update_signal_fences(task, local_tasks + i); if (err) { nvdla_dbg_err(pdev, "fail update postfence%d", i + 1); goto fail_to_update_postfences; diff --git a/drivers/video/tegra/host/nvdla/nvdla_queue.c b/drivers/video/tegra/host/nvdla/nvdla_queue.c index 5acf3d29..7f8d48b7 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_queue.c +++ b/drivers/video/tegra/host/nvdla/nvdla_queue.c @@ -651,7 +651,6 @@ static int nvdla_fill_wait_fence_action(struct nvdla_task *task, fence->syncpoint_value); } else { dma_addr_t syncpt_addr; - nvdla_dbg_info(pdev, "GoS missing"); syncpt_addr = nvhost_syncpt_address( @@ -945,9 +944,6 @@ static int nvdla_fill_postactions(struct nvdla_task *task) } } - /* reset fence counter */ - task->fence_counter = 0; - /* fill all postactions */ for (i = 0; i < task->num_postfences; i++) { /* update action */ @@ -992,8 +988,12 @@ static int nvdla_fill_preactions(struct nvdla_task *task) start = next = (u8 *)task_desc + preactionlist_of; - /* fill all preactions */ + /* fill all preactions wait */ for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_WAIT) + continue; + + /* update action */ err = nvdla_fill_wait_fence_action(task, &task->prefences[i], &task->prefences_sem_dmabuf[i], @@ -1016,6 +1016,24 @@ static int nvdla_fill_preactions(struct nvdla_task *task) } } + /* fill all preactions signals */ + for (i = 0; i < task->num_prefences; i++) { + /* update action */ + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + err = nvdla_fill_signal_fence_action(task, + &task->prefences[i], + &task->prefences_sem_dmabuf[i], + &next); + if (err < 0) { + nvdla_dbg_err(pdev, + "fail to fill fence sig action [%d]", + i); + goto fail; + } + } + /* update end of action list */ next = add_opcode(next, ACTION_TERMINATE); @@ -1077,6 +1095,9 @@ int nvdla_fill_task_desc(struct nvdla_task *task) nvdla_update_gos(pdev); + /* reset fence counter */ + task->fence_counter = 0; + /* fill pre actions */ nvdla_fill_preactions(task); @@ -1187,8 +1208,30 @@ int nvdla_emulator_submit(struct nvdla_queue *queue, struct nvdla_emu_task *task /* reset fence counter */ task->fence_counter = 0; + + /* fill all preactions */ + for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + /* update action */ + switch (task->prefences[i].type) { + case NVDEV_FENCE_TYPE_SYNCPT: + case NVDEV_FENCE_TYPE_SYNC_FD: { + task->fence_counter = task->fence_counter + 1; + break; + } + default: + nvdla_dbg_err(pdev, "Invalid prefence sync type[%d]", + task->prefences[i].type); + return -EINVAL; + } + } + /* fill all postactions */ for (i = 0; i < task->num_postfences; i++) { + if (task->postfences[i].action != NVDEV_FENCE_SIGNAL) + continue; /* update action */ switch (task->postfences[i].type) { @@ -1212,9 +1255,31 @@ int nvdla_emulator_submit(struct nvdla_queue *queue, struct nvdla_emu_task *task queue->syncpt_id, task->fence, task, task->fence_counter); - /* Update postfences for all */ + /* Update signal fences for all */ counter = task->fence_counter - 1; + for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + if ((task->prefences[i].type == NVDEV_FENCE_TYPE_SYNCPT) || + (task->prefences[i].type == NVDEV_FENCE_TYPE_SYNC_FD)) { + task->prefences[i].syncpoint_index = + queue->syncpt_id; + task->prefences[i].syncpoint_value = + task->fence - counter; + + nvdla_dbg_info(pdev, "[%d] prefence set[%u]:[%u]", + i, task->prefences[i].syncpoint_index, + task->prefences[i].syncpoint_value); + + counter = counter - 1; + } + } + for (i = 0; i < task->num_postfences; i++) { + if (task->postfences[i].action != NVDEV_FENCE_SIGNAL) + continue; + if ((task->postfences[i].type == NVDEV_FENCE_TYPE_SYNCPT) || (task->postfences[i].type == NVDEV_FENCE_TYPE_SYNC_FD)) { task->postfences[i].syncpoint_index = @@ -1233,7 +1298,7 @@ int nvdla_emulator_submit(struct nvdla_queue *queue, struct nvdla_emu_task *task return 0; } -int nvdla_get_postfences(struct nvdla_queue *queue, void *in_task) +int nvdla_get_signal_fences(struct nvdla_queue *queue, void *in_task) { struct nvdla_task *task = (struct nvdla_task *)in_task; struct platform_device *pdev = queue->pool->pdev; @@ -1251,9 +1316,31 @@ int nvdla_get_postfences(struct nvdla_queue *queue, void *in_task) task_fence = nvhost_syncpt_read_maxval(pdev, queue->syncpt_id) + task->fence_counter; - /* Update postfences for all */ + /* Update fences signal updates for both prefence and postfence */ counter = task->fence_counter - 1; + for (i = 0; i < task->num_prefences; i++) { + if (task->prefences[i].action != NVDEV_FENCE_SIGNAL) + continue; + + if ((task->prefences[i].type == NVDEV_FENCE_TYPE_SYNCPT) || + (task->prefences[i].type == NVDEV_FENCE_TYPE_SYNC_FD)) { + task->prefences[i].syncpoint_index = + queue->syncpt_id; + task->prefences[i].syncpoint_value = + task_fence - counter; + + nvdla_dbg_info(pdev, "[%d] prefence set[%u]:[%u]", + i, task->prefences[i].syncpoint_index, + task->prefences[i].syncpoint_value); + + counter = counter - 1; + } + } + for (i = 0; i < task->num_postfences; i++) { + if (task->postfences[i].action != NVDEV_FENCE_SIGNAL) + continue; + if ((task->postfences[i].type == NVDEV_FENCE_TYPE_SYNCPT) || (task->postfences[i].type == NVDEV_FENCE_TYPE_SYNC_FD)) { task->postfences[i].syncpoint_index = diff --git a/include/uapi/linux/nvhost_nvdla_ioctl.h b/include/uapi/linux/nvhost_nvdla_ioctl.h index 5cd77743..41652321 100644 --- a/include/uapi/linux/nvhost_nvdla_ioctl.h +++ b/include/uapi/linux/nvhost_nvdla_ioctl.h @@ -3,7 +3,7 @@ * * Tegra NvDLA Driver * - * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2019, 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, @@ -160,15 +160,17 @@ struct nvdla_ioctl_submit_task { * struct nvdla_ioctl_emu_submit_task structure for single emulator task * information * + * @num_prefences number of pre-fences in task * @num_postfences number of post-fences in task - * @reserved reserved for padding and future use - * @postfences pointer to post-fence struct table + * @prefences pointer to pre-fence struct table + * @postfences pointer to post-fence struct table * */ struct nvdla_ioctl_emu_submit_task { + __u32 num_prefences; __u32 num_postfences; - __u32 reserved; + __u64 prefences; __u64 postfences; };