video: driver: add fence support
Add fence support for decoder output buffers for the consumer to use it to improve latency. Change-Id: I7384b4a9793248988a2d2d546a535f26636d5bb3 Signed-off-by: Maheshwar Ajja <quic_majja@quicinc.com>
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

parent
4b2e594b7b
commit
ef829ce44f
1
Kbuild
1
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
|
||||
|
21
driver/vidc/inc/msm_vidc_fence.h
Normal file
21
driver/vidc/inc/msm_vidc_fence.h
Normal file
@@ -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__
|
@@ -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;
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
@@ -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 {
|
||||
|
@@ -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__);
|
||||
|
@@ -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);
|
||||
|
162
driver/vidc/src/msm_vidc_fence.c
Normal file
162
driver/vidc/src/msm_vidc_fence.c
Normal file
@@ -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", "");
|
||||
}
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user