diff --git a/drivers/video/tegra/host/nvdla/dla_os_interface.h b/drivers/video/tegra/host/nvdla/dla_os_interface.h index d2204aaa..d6efca15 100644 --- a/drivers/video/tegra/host/nvdla/dla_os_interface.h +++ b/drivers/video/tegra/host/nvdla/dla_os_interface.h @@ -87,6 +87,7 @@ /* write actions */ #define ACTION_WRITE_SEM 0x80 #define ACTION_WRITE_TS_SEM 0x83 +#define ACTION_WRITE_TIMESTAMP 0x87 #define ACTION_WRITE_GOS 0xA0 #define ACTION_WRITE_TASK_STATUS 0xC1 @@ -231,6 +232,17 @@ struct dla_action_task_status { uint16_t status; } __attribute__ ((packed)); +/** + * Timestamp update action structure + * + * OPCODE = 0x87 + * + * @address: Address to write timestamp + */ +struct dla_action_timestamp { + uint64_t address; +} __attribute__ ((packed)); + /** * Status notifier structure * diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index 11e014bd..2aa3a6cc 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -103,6 +103,7 @@ #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 MAX_NUM_NVDLA_OUT_TIMESTAMP 32 #define NUM_PROFILING_POSTACTION 1 #define MAX_COMMANDS_PER_DEVICE 1 @@ -267,12 +268,16 @@ struct nvdla_task { struct nvdla_status_notify in_task_status[MAX_NUM_NVDLA_IN_TASK_STATUS]; struct nvdla_status_notify sof_task_status[MAX_NUM_NVDLA_OUT_TASK_STATUS]; struct nvdla_status_notify eof_task_status[MAX_NUM_NVDLA_OUT_TASK_STATUS]; + struct nvdla_mem_handle sof_timestamps[MAX_NUM_NVDLA_OUT_TIMESTAMP]; + struct nvdla_mem_handle eof_timestamps[MAX_NUM_NVDLA_OUT_TIMESTAMP]; struct nvdla_mem_handle memory_handles[NVDLA_MAX_BUFFERS_PER_TASK]; u8 num_prefences; u8 num_postfences; u8 num_in_task_status; u8 num_sof_task_status; u8 num_eof_task_status; + u8 num_sof_timestamps; + u8 num_eof_timestamps; u32 num_addresses; u32 fence; u32 fence_counter; @@ -290,6 +295,8 @@ struct nvdla_task { struct dma_buf *postfences_sem_dmabuf[MAX_NUM_NVDLA_POSTFENCES]; struct dma_buf *sof_task_status_dmabuf[MAX_NUM_NVDLA_OUT_TASK_STATUS]; struct dma_buf *eof_task_status_dmabuf[MAX_NUM_NVDLA_OUT_TASK_STATUS]; + struct dma_buf *sof_timestamps_dmabuf[MAX_NUM_NVDLA_OUT_TIMESTAMP]; + struct dma_buf *eof_timestamps_dmabuf[MAX_NUM_NVDLA_OUT_TIMESTAMP]; }; struct dla_mem_addr { diff --git a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c index 04652af4..4987ee3b 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c +++ b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c @@ -396,6 +396,24 @@ static int nvdla_get_actions(struct nvdla_ioctl_submit_task *user_task, goto fail; } + /* get sof timestamps */ + if (copy_from_user(task->sof_timestamps, + (void __user*)user_task->sof_timestamps, + (task->num_sof_timestamps * sizeof(struct nvdla_mem_handle)))) { + err = -EFAULT; + nvdla_dbg_err(pdev, "failed to copy sof timestamps"); + goto fail; + } + + /* get eof timestamps */ + if (copy_from_user(task->eof_timestamps, + (void __user*)user_task->eof_timestamps, + (task->num_eof_timestamps * sizeof(struct nvdla_mem_handle)))) { + err = -EFAULT; + nvdla_dbg_err(pdev, "failed to copy eof timestamps"); + goto fail; + } + nvdla_dbg_info(pdev, "copying actions done"); fail: @@ -640,6 +658,18 @@ 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_sof_timestamps > MAX_NUM_NVDLA_OUT_TIMESTAMP) { + pr_err("sof timestamps[%u] crossing expected[%d]\n", + in_task->num_sof_timestamps, + MAX_NUM_NVDLA_OUT_TIMESTAMP); + return -EINVAL; + } + if (in_task->num_eof_timestamps > MAX_NUM_NVDLA_OUT_TIMESTAMP) { + pr_err("eof timestamps[%u] crossing expected[%d]\n", + in_task->num_eof_timestamps, + MAX_NUM_NVDLA_OUT_TIMESTAMP); + return -EINVAL; + } if (in_task->num_addresses < 1) { pr_err("num addresses[%u] should be min one\n", in_task->num_addresses); @@ -683,6 +713,8 @@ static int nvdla_fill_task(struct nvdla_queue *queue, task->num_in_task_status = local_task->num_input_task_status; task->num_sof_task_status = local_task->num_sof_task_status; task->num_eof_task_status = local_task->num_eof_task_status; + task->num_sof_timestamps = local_task->num_sof_timestamps; + task->num_eof_timestamps = local_task->num_eof_timestamps; task->num_addresses = local_task->num_addresses; task->timeout = local_task->timeout; @@ -731,6 +763,9 @@ static void nvdla_dump_task(struct nvdla_task *task) task->num_in_task_status, task->num_sof_task_status, task->num_eof_task_status); + nvdla_dbg_info(pdev, "num_sof_timestamps[%u] num_eof_timestamps[%u]", + task->num_sof_timestamps, + task->num_eof_timestamps); nvdla_dbg_info(pdev, "num_addresses[%u]", task->num_addresses); for (i = 0; i < task->num_prefences; i++) { @@ -783,6 +818,20 @@ static void nvdla_dump_task(struct nvdla_task *task) task->eof_task_status[i].status); } + for (i = 0; i < task->num_sof_timestamps; i++) { + nvdla_dbg_info(pdev, "SOF timestamp[%d]:" + "handle[%u] offset[%u]", + i, task->sof_timestamps[i].handle, + task->sof_timestamps[i].offset); + } + + for (i = 0; i < task->num_eof_timestamps; i++) { + nvdla_dbg_info(pdev, "EOF timestamp[%d]:" + "handle[%u] offset[%u]", + i, task->eof_timestamps[i].handle, + task->eof_timestamps[i].offset); + } + for (i = 0; i < task->num_addresses; i++) { nvdla_dbg_info(pdev, "Memory Handles[%d]:" "handle[%u] offset[%u]", diff --git a/drivers/video/tegra/host/nvdla/nvdla_queue.c b/drivers/video/tegra/host/nvdla/nvdla_queue.c index 0ce4e700..10c4b145 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_queue.c +++ b/drivers/video/tegra/host/nvdla/nvdla_queue.c @@ -228,6 +228,25 @@ static int nvdla_unmap_task_memory(struct nvdla_task *task) } nvdla_dbg_fn(pdev, "all out task status unmaped"); + /* unpin output timestamp memory */ + for (ii = 0; ii < task->num_sof_timestamps; ii++) { + if (task->sof_timestamps[ii].handle) { + nvdla_buffer_submit_unpin(task->buffers, + &task->sof_timestamps_dmabuf[ii], 1); + dma_buf_put(task->sof_timestamps_dmabuf[ii]); + } + } + + for (ii = 0; ii < task->num_eof_timestamps; ii++) { + if (task->eof_timestamps[ii].handle) { + nvdla_buffer_submit_unpin(task->buffers, + &task->eof_timestamps_dmabuf[ii], 1); + dma_buf_put(task->eof_timestamps_dmabuf[ii]); + } + } + nvdla_dbg_fn(pdev, "all out timestamps unmaped"); + + return 0; } @@ -261,12 +280,15 @@ static void nvdla_task_syncpt_reset(struct nvhost_syncpt *syncpt, static inline int nvdla_get_max_preaction_size(void) { return (((MAX_NUM_NVDLA_PREFENCES + MAX_NUM_NVDLA_IN_TASK_STATUS + - MAX_NUM_NVDLA_OUT_TASK_STATUS) * + MAX_NUM_NVDLA_OUT_TASK_STATUS + + MAX_NUM_NVDLA_OUT_TIMESTAMP) * sizeof(struct dla_action_opcode)) + (MAX_NUM_NVDLA_PREFENCES * sizeof(struct dla_action_semaphore)) + ((MAX_NUM_NVDLA_IN_TASK_STATUS + MAX_NUM_NVDLA_OUT_TASK_STATUS) * sizeof(struct dla_action_task_status)) + + (MAX_NUM_NVDLA_OUT_TIMESTAMP * + sizeof(struct dla_action_timestamp)) + sizeof(struct dla_action_opcode)); } @@ -274,6 +296,7 @@ static inline int nvdla_get_max_postaction_size(void) { return (((MAX_NUM_NVDLA_POSTFENCES + MAX_NUM_NVDLA_OUT_TASK_STATUS + + MAX_NUM_NVDLA_OUT_TIMESTAMP + NUM_PROFILING_POSTACTION) * sizeof(struct dla_action_opcode)) + (MAX_NUM_NVDLA_POSTFENCES * @@ -281,6 +304,8 @@ static inline int nvdla_get_max_postaction_size(void) ((MAX_NUM_NVDLA_OUT_TASK_STATUS + NUM_PROFILING_POSTACTION) * sizeof(struct dla_action_task_status)) + + (MAX_NUM_NVDLA_OUT_TIMESTAMP * + sizeof(struct dla_action_timestamp)) + sizeof(struct dla_action_opcode)); } @@ -436,6 +461,18 @@ static u8 *add_status_action(u8 *mem, uint8_t op, uint64_t addr, return mem + sizeof(struct dla_action_task_status); } +static u8 *add_timestamp_action(u8 *mem, uint8_t op, uint64_t addr) +{ + struct dla_action_timestamp *action; + + mem = add_opcode(mem, op); + + action = (struct dla_action_timestamp *)mem; + action->address = addr; + + return mem + sizeof(struct dla_action_timestamp); +} + static u8 *add_gos_action(u8 *mem, uint8_t op, uint8_t index, uint16_t offset, uint32_t value) { @@ -918,6 +955,50 @@ fail: return err; } +static int nvdla_fill_timestamp_write_action(struct nvdla_task *task, + struct nvdla_mem_handle *timestamp, + struct dma_buf **dma_buf, + u8 **mem_next) +{ + int err = 0; + + struct nvdla_buffers *buffers = task->buffers; + struct nvdla_queue *queue = task->queue; + struct platform_device *pdev = queue->pool->pdev; + dma_addr_t dma_addr; + size_t dma_size; + + u8 *next = *mem_next; + + nvdla_dbg_info(pdev, "h[%u] o[%u]", + timestamp->handle, + timestamp->offset); + + *dma_buf = dma_buf_get(timestamp->handle); + if (IS_ERR_OR_NULL(*dma_buf)) { + *dma_buf = NULL; + nvdla_dbg_err(pdev, "fail to get buf"); + err = -EINVAL; + goto fail; + } + + if (nvdla_buffer_submit_pin(buffers, + dma_buf, 1, &dma_addr, &dma_size, NULL)) { + nvdla_dbg_err(pdev, "fail to pin timestamp"); + err = -EINVAL; + goto fail; + } + + next = add_timestamp_action(next, ACTION_WRITE_TIMESTAMP, + dma_addr + timestamp->offset); + + *mem_next = next; + +fail: + return err; +} + + static int nvdla_fill_postactions(struct nvdla_task *task) { int err = 0; @@ -941,6 +1022,20 @@ static int nvdla_fill_postactions(struct nvdla_task *task) next = add_status_action(next, ACTION_WRITE_TASK_STATUS, task->task_desc_pa + nvdla_profile_status_offset(task), 0); + /* fill eof timestamp actions */ + for (i = 0; i < task->num_eof_timestamps; i++) { + err = nvdla_fill_timestamp_write_action(task, + &task->eof_timestamps[i], + &task->eof_timestamps_dmabuf[i], + &next); + if (err < 0) { + nvdla_dbg_err(pdev, + "failed to fill eof timestamp[%d]", + i); + goto fail; + } + } + /* fill output task status */ for (i = 0; i < task->num_eof_task_status; i++) { err = nvdla_fill_taskstatus_write_action(task, @@ -1043,6 +1138,20 @@ static int nvdla_fill_preactions(struct nvdla_task *task) } } + /* fill sof timestamp actions */ + for (i = 0; i < task->num_sof_timestamps; i++) { + err = nvdla_fill_timestamp_write_action(task, + &task->sof_timestamps[i], + &task->sof_timestamps_dmabuf[i], + &next); + if (err < 0) { + nvdla_dbg_err(pdev, + "failed to fill sof timestamp[%d]", + i); + goto fail; + } + } + /* fill all preactions signals */ for (i = 0; i < task->num_prefences; i++) { /* update action */ diff --git a/include/uapi/linux/nvhost_nvdla_ioctl.h b/include/uapi/linux/nvhost_nvdla_ioctl.h index a3e750ac..3d85c544 100644 --- a/include/uapi/linux/nvhost_nvdla_ioctl.h +++ b/include/uapi/linux/nvhost_nvdla_ioctl.h @@ -79,7 +79,7 @@ struct nvdla_pin_unpin_args { struct nvdla_submit_args { __u64 tasks; __u16 num_tasks; -#define MAX_TASKS_PER_SUBMIT 24 +#define MAX_TASKS_PER_SUBMIT 16 #define NVDLA_SUBMIT_FLAGS_ATOMIC (1 << 0) __u16 flags; __u32 version; @@ -127,6 +127,8 @@ struct nvdla_mem_handle { * @num_input_task_status number of input task status * @num_sof_task_status number of sof task status * @num_eof_task_status number of eof task status + * @num_sof_timestamps number of sof timestamp + * @num_eof_timestamps number of eof timestamp * @flags flags for bitwise task info embeddeing * @reserved reserved for future use * @prefences pointer to pre-fence struct table @@ -134,6 +136,8 @@ struct nvdla_mem_handle { * @input_task_status pointer to input task status struct table * @sof_task_status pointer to sof task status struct table * @eof_task_status pointer to eof task status struct table + * @sof_timestamps pointer to sof timestamp handle list + * @eof_timestamps pointer to eof timestamp handle list * @num_addresses total number of addressed passed in structure * @address_list pointer to address list * @timeout task timeout @@ -145,7 +149,9 @@ struct nvdla_ioctl_submit_task { __u8 num_input_task_status; __u8 num_sof_task_status; __u8 num_eof_task_status; - __u8 reserved0[3]; + __u8 num_sof_timestamps; + __u8 num_eof_timestamps; + __u8 reserved0[1]; #define NVDLA_MAX_BUFFERS_PER_TASK (6144) __u32 num_addresses; __u16 flags; @@ -157,6 +163,8 @@ struct nvdla_ioctl_submit_task { __u64 input_task_status; __u64 sof_task_status; __u64 eof_task_status; + __u64 sof_timestamps; + __u64 eof_timestamps; __u64 address_list; __u64 timeout; };