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_platform.o \
|
||||||
driver/vidc/src/msm_vidc_debug.o \
|
driver/vidc/src/msm_vidc_debug.o \
|
||||||
driver/vidc/src/msm_vidc_memory.o \
|
driver/vidc/src/msm_vidc_memory.o \
|
||||||
|
driver/vidc/src/msm_vidc_fence.o \
|
||||||
driver/vidc/src/venus_hfi.o \
|
driver/vidc/src/venus_hfi.o \
|
||||||
driver/vidc/src/hfi_packet.o \
|
driver/vidc/src/hfi_packet.o \
|
||||||
driver/vidc/src/venus_hfi_response.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_statistics stats;
|
||||||
struct msm_vidc_inst_capability *capabilities;
|
struct msm_vidc_inst_capability *capabilities;
|
||||||
struct completion completions[MAX_SIGNAL];
|
struct completion completions[MAX_SIGNAL];
|
||||||
|
struct msm_vidc_fence_context fence;
|
||||||
enum priority_level priority_level;
|
enum priority_level priority_level;
|
||||||
u32 firmware_priority;
|
u32 firmware_priority;
|
||||||
bool active;
|
bool active;
|
||||||
|
@@ -9,6 +9,9 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
#include <linux/workqueue.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-dev.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-ioctl.h>
|
#include <media/v4l2-ioctl.h>
|
||||||
@@ -780,6 +783,20 @@ struct msm_vidc_power {
|
|||||||
u32 fw_cf;
|
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 msm_vidc_alloc {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
enum msm_vidc_buffer_type type;
|
enum msm_vidc_buffer_type type;
|
||||||
@@ -827,6 +844,7 @@ struct msm_vidc_buffer {
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
enum msm_vidc_buffer_attributes attr;
|
enum msm_vidc_buffer_attributes attr;
|
||||||
|
struct msm_vidc_fence *fence;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msm_vidc_buffers {
|
struct msm_vidc_buffers {
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include "msm_vidc_debug.h"
|
#include "msm_vidc_debug.h"
|
||||||
#include "msm_vidc_control.h"
|
#include "msm_vidc_control.h"
|
||||||
#include "msm_vidc_power.h"
|
#include "msm_vidc_power.h"
|
||||||
|
#include "msm_vidc_fence.h"
|
||||||
#include "msm_vidc_memory.h"
|
#include "msm_vidc_memory.h"
|
||||||
#include "venus_hfi_response.h"
|
#include "venus_hfi_response.h"
|
||||||
#include "msm_vidc.h"
|
#include "msm_vidc.h"
|
||||||
@@ -980,6 +981,10 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
rc = msm_vidc_fence_init(inst);
|
||||||
|
if (rc)
|
||||||
|
goto error;
|
||||||
|
|
||||||
rc = msm_vidc_add_session(inst);
|
rc = msm_vidc_add_session(inst);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
i_vpr_e(inst, "%s: failed to get session id\n", __func__);
|
i_vpr_e(inst, "%s: failed to get session id\n", __func__);
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include "msm_vidc.h"
|
#include "msm_vidc.h"
|
||||||
#include "msm_vdec.h"
|
#include "msm_vdec.h"
|
||||||
#include "msm_venc.h"
|
#include "msm_venc.h"
|
||||||
|
#include "msm_vidc_fence.h"
|
||||||
#include "venus_hfi.h"
|
#include "venus_hfi.h"
|
||||||
#include "venus_hfi_response.h"
|
#include "venus_hfi_response.h"
|
||||||
#include "hfi_packet.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;
|
int rc = 0;
|
||||||
struct msm_vidc_buffer *buf;
|
struct msm_vidc_buffer *buf;
|
||||||
enum msm_vidc_allow allow;
|
enum msm_vidc_allow allow;
|
||||||
|
const int fence_enabled = 0;
|
||||||
|
|
||||||
if (!inst || !vb2) {
|
if (!inst || !vb2) {
|
||||||
d_vpr_e("%s: invalid params\n", __func__);
|
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)
|
if (!buf)
|
||||||
return -EINVAL;
|
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);
|
allow = msm_vidc_allow_qbuf(inst, vb2->type);
|
||||||
if (allow == MSM_VIDC_DISALLOW) {
|
if (allow == MSM_VIDC_DISALLOW) {
|
||||||
i_vpr_e(inst, "%s: qbuf not allowed\n", __func__);
|
i_vpr_e(inst, "%s: qbuf not allowed\n", __func__);
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto exit;
|
||||||
} else if (allow == MSM_VIDC_DEFER) {
|
} else if (allow == MSM_VIDC_DEFER) {
|
||||||
print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
|
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));
|
msm_vidc_scale_power(inst, is_input_buffer(buf->type));
|
||||||
|
|
||||||
rc = msm_vidc_queue_buffer(inst, buf);
|
rc = msm_vidc_queue_buffer(inst, buf);
|
||||||
if (rc)
|
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;
|
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) {
|
list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
|
||||||
print_vidc_buffer(VIDC_ERR, "err ", "destroying ", inst, buf);
|
print_vidc_buffer(VIDC_ERR, "err ", "destroying ", inst, buf);
|
||||||
|
msm_vidc_fence_destroy(inst, buf);
|
||||||
if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE))
|
if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE))
|
||||||
msm_vidc_vb2_buffer_done(inst, buf);
|
msm_vidc_vb2_buffer_done(inst, buf);
|
||||||
msm_vidc_put_driver_buf(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);
|
struct msm_vidc_inst, kref);
|
||||||
|
|
||||||
i_vpr_h(inst, "%s()\n", __func__);
|
i_vpr_h(inst, "%s()\n", __func__);
|
||||||
|
msm_vidc_fence_deinit(inst);
|
||||||
msm_vidc_event_queue_deinit(inst);
|
msm_vidc_event_queue_deinit(inst);
|
||||||
msm_vidc_vb2_queue_deinit(inst);
|
msm_vidc_vb2_queue_deinit(inst);
|
||||||
msm_vidc_debugfs_deinit_inst(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_vdec.h"
|
||||||
#include "msm_vidc_control.h"
|
#include "msm_vidc_control.h"
|
||||||
#include "msm_vidc_memory.h"
|
#include "msm_vidc_memory.h"
|
||||||
|
#include "msm_vidc_fence.h"
|
||||||
|
|
||||||
#define in_range(range, val) (((range.begin) < (val)) && ((range.end) > (val)))
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* signal the fence asap */
|
||||||
|
msm_vidc_fence_signal(inst, buf);
|
||||||
|
|
||||||
buf->data_offset = buffer->data_offset;
|
buf->data_offset = buffer->data_offset;
|
||||||
buf->data_size = buffer->data_size;
|
buf->data_size = buffer->data_size;
|
||||||
buf->timestamp = buffer->timestamp;
|
buf->timestamp = buffer->timestamp;
|
||||||
|
Reference in New Issue
Block a user