diff --git a/Kbuild b/Kbuild index 9739308e2c..a5c21993d5 100644 --- a/Kbuild +++ b/Kbuild @@ -69,6 +69,7 @@ msm_video-objs += driver/vidc/src/msm_vidc_v4l2.o \ driver/vidc/src/msm_vidc_platform.o \ driver/vidc/src/msm_vidc_debug.o \ driver/vidc/src/msm_vidc_memory.o \ + driver/vidc/src/msm_vidc_fence.o \ driver/vidc/src/venus_hfi.o \ driver/vidc/src/hfi_packet.o \ driver/vidc/src/venus_hfi_response.o diff --git a/driver/vidc/inc/msm_vidc_fence.h b/driver/vidc/inc/msm_vidc_fence.h new file mode 100644 index 0000000000..87518cf064 --- /dev/null +++ b/driver/vidc/inc/msm_vidc_fence.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_FENCE_H__ +#define __H_MSM_VIDC_FENCE_H__ + +#include "msm_vidc_inst.h" +#include "msm_vidc_buffer.h" + +int msm_vidc_fence_create(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); +int msm_vidc_fence_signal(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); +void msm_vidc_fence_destroy(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); +int msm_vidc_fence_init(struct msm_vidc_inst *inst); +void msm_vidc_fence_deinit(struct msm_vidc_inst *inst); + +#endif // __H_MSM_VIDC_FENCE_H__ diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 9e294bcf3f..a579dc4620 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -153,6 +153,7 @@ struct msm_vidc_inst { struct msm_vidc_statistics stats; struct msm_vidc_inst_capability *capabilities; struct completion completions[MAX_SIGNAL]; + struct msm_vidc_fence_context fence; enum priority_level priority_level; u32 firmware_priority; bool active; diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 3d0adb460f..2c38f34a21 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -780,6 +783,20 @@ struct msm_vidc_power { u32 fw_cf; }; +struct msm_vidc_fence_context { + char name[MAX_NAME_LENGTH]; + u64 ctx_num; + u64 seq_num; +}; + +struct msm_vidc_fence { + struct dma_fence dma_fence; + char name[MAX_NAME_LENGTH]; + spinlock_t lock; + struct sync_file *sync_file; + int fd; +}; + struct msm_vidc_alloc { struct list_head list; enum msm_vidc_buffer_type type; @@ -827,6 +844,7 @@ struct msm_vidc_buffer { u32 flags; u64 timestamp; enum msm_vidc_buffer_attributes attr; + struct msm_vidc_fence *fence; }; struct msm_vidc_buffers { diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index d24620f0aa..ef136a6b61 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -16,6 +16,7 @@ #include "msm_vidc_debug.h" #include "msm_vidc_control.h" #include "msm_vidc_power.h" +#include "msm_vidc_fence.h" #include "msm_vidc_memory.h" #include "venus_hfi_response.h" #include "msm_vidc.h" @@ -980,6 +981,10 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) if (rc) goto error; + rc = msm_vidc_fence_init(inst); + if (rc) + goto error; + rc = msm_vidc_add_session(inst); if (rc) { i_vpr_e(inst, "%s: failed to get session id\n", __func__); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 2c103af88b..e100ca81ec 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -19,6 +19,7 @@ #include "msm_vidc.h" #include "msm_vdec.h" #include "msm_venc.h" +#include "msm_vidc_fence.h" #include "venus_hfi.h" #include "venus_hfi_response.h" #include "hfi_packet.h" @@ -3255,6 +3256,7 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer * int rc = 0; struct msm_vidc_buffer *buf; enum msm_vidc_allow allow; + const int fence_enabled = 0; if (!inst || !vb2) { d_vpr_e("%s: invalid params\n", __func__); @@ -3265,21 +3267,35 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer * if (!buf) return -EINVAL; + if (fence_enabled && is_decode_session(inst) && + is_output_buffer(buf->type)) { + rc = msm_vidc_fence_create(inst, buf); + if (rc) + return rc; + } + allow = msm_vidc_allow_qbuf(inst, vb2->type); if (allow == MSM_VIDC_DISALLOW) { i_vpr_e(inst, "%s: qbuf not allowed\n", __func__); - return -EINVAL; + rc = -EINVAL; + goto exit; } else if (allow == MSM_VIDC_DEFER) { print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); - return 0; + rc = 0; + goto exit; } msm_vidc_scale_power(inst, is_input_buffer(buf->type)); rc = msm_vidc_queue_buffer(inst, buf); if (rc) - return rc; + goto exit; +exit: + if (rc) { + i_vpr_e(inst, "%s: qbuf failed\n", __func__); + msm_vidc_fence_destroy(inst, buf); + } return rc; } @@ -5196,6 +5212,7 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) list_for_each_entry_safe(buf, dummy, &buffers->list, list) { print_vidc_buffer(VIDC_ERR, "err ", "destroying ", inst, buf); + msm_vidc_fence_destroy(inst, buf); if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) msm_vidc_vb2_buffer_done(inst, buf); msm_vidc_put_driver_buf(inst, buf); @@ -5244,6 +5261,7 @@ static void msm_vidc_close_helper(struct kref *kref) struct msm_vidc_inst, kref); i_vpr_h(inst, "%s()\n", __func__); + msm_vidc_fence_deinit(inst); msm_vidc_event_queue_deinit(inst); msm_vidc_vb2_queue_deinit(inst); msm_vidc_debugfs_deinit_inst(inst); diff --git a/driver/vidc/src/msm_vidc_fence.c b/driver/vidc/src/msm_vidc_fence.c new file mode 100644 index 0000000000..b375ba38b8 --- /dev/null +++ b/driver/vidc/src/msm_vidc_fence.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_fence.h" +#include "msm_vidc_debug.h" + +static const char *msm_vidc_dma_fence_get_driver_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_dma_fence_get_driver_name: invalid fence"; +} + +static const char *msm_vidc_dma_fence_get_timeline_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_dma_fence_get_timeline_name: invalid fence"; +} + +static void msm_vidc_dma_fence_release(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + d_vpr_l("%s: name %s\n", __func__, fence->name); + kfree(fence); + } else { + d_vpr_e("%s: invalid fence\n", __func__); + } +} + +static const struct dma_fence_ops msm_vidc_dma_fence_ops = { + .get_driver_name = msm_vidc_dma_fence_get_driver_name, + .get_timeline_name = msm_vidc_dma_fence_get_timeline_name, + .release = msm_vidc_dma_fence_release, +}; + +int msm_vidc_fence_create(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct msm_vidc_fence *fence; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return -ENOMEM; + + spin_lock_init(&fence->lock); + dma_fence_init(&fence->dma_fence, &msm_vidc_dma_fence_ops, + &fence->lock, inst->fence.ctx_num, inst->fence.seq_num++); + snprintf(fence->name, sizeof(fence->name), "%s: %llu", + inst->fence.name, inst->fence.seq_num); + + fence->fd = get_unused_fd_flags(0); + if (fence->fd < 0) { + i_vpr_e(inst, "%s: getting fd (%d) failed\n", __func__, + fence->fd); + rc = -EINVAL; + goto err_fd; + } + fence->sync_file = sync_file_create(&fence->dma_fence); + if (!fence->sync_file) { + i_vpr_e(inst, "%s: sync_file_create failed\n", __func__); + rc = -EINVAL; + goto err_sync_file; + } + fd_install(fence->fd, fence->sync_file->file); + + buf->fence = fence; + i_vpr_h(inst, "%s: created %s\n", __func__, fence->name); + return 0; + +err_sync_file: + put_unused_fd(fence->fd); +err_fd: + dma_fence_put(&fence->dma_fence); + buf->fence = NULL; + return rc; +} + +int msm_vidc_fence_signal(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + if (!buf->fence) + return 0; + + i_vpr_l(inst, "%s: fence %s\n", __func__, buf->fence->name); + dma_fence_signal(&buf->fence->dma_fence); + dma_fence_put(&buf->fence->dma_fence); + buf->fence = NULL; + + return rc; +} + +void msm_vidc_fence_destroy(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + if (!buf->fence) + return; + + i_vpr_e(inst, "%s: fence %s\n", __func__, buf->fence->name); + dma_fence_set_error(&buf->fence->dma_fence, -EINVAL); + dma_fence_signal(&buf->fence->dma_fence); + dma_fence_put(&buf->fence->dma_fence); + buf->fence = NULL; +} + +int msm_vidc_fence_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + inst->fence.ctx_num = dma_fence_context_alloc(1); + snprintf(inst->fence.name, sizeof(inst->fence.name), + "msm_vidc_fence: %s: %llu", inst->debug_str, + inst->fence.ctx_num); + i_vpr_h(inst, "%s: %s\n", __func__, inst->fence.name); + + return rc; +} + +void msm_vidc_fence_deinit(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + i_vpr_h(inst, "%s: %s\n", __func__, inst->fence.name); + inst->fence.ctx_num = 0; + snprintf(inst->fence.name, sizeof(inst->fence.name), "%s", ""); +} diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index 440b4dd666..4dcac18b7a 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -13,6 +13,7 @@ #include "msm_vdec.h" #include "msm_vidc_control.h" #include "msm_vidc_memory.h" +#include "msm_vidc_fence.h" #define in_range(range, val) (((range.begin) < (val)) && ((range.end) > (val))) @@ -823,6 +824,9 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, return 0; } + /* signal the fence asap */ + msm_vidc_fence_signal(inst, buf); + buf->data_offset = buffer->data_offset; buf->data_size = buffer->data_size; buf->timestamp = buffer->timestamp;