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:
Maheshwar Ajja
2022-01-19 20:54:17 -08:00
committed by Gerrit - the friendly Code Review server
parent 4b2e594b7b
commit ef829ce44f
8 changed files with 233 additions and 3 deletions

1
Kbuild
View File

@@ -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

View 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__

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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__);

View File

@@ -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);

View 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", "");
}

View File

@@ -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;