media: venus: vdec: decoded picture buffer handling during reconfig sequence

In existing implementation, driver is freeing and un-mapping all the
decoded picture buffers(DPB) as part of dynamic resolution change(DRC)
handling. As a result, when firmware try to access the DPB buffer, from
previous sequence, SMMU context fault is seen due to the buffer being
already unmapped.

With this change, driver defines ownership of each DPB buffer. If a buffer
is owned by firmware, driver would skip from un-mapping the same.

Signed-off-by: Mansur Alisha Shaik <mansur@codeaurora.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Mansur Alisha Shaik 2021-10-20 07:44:08 +01:00 committed by Mauro Carvalho Chehab
parent 3227a8f7cf
commit 40d87aafee
4 changed files with 60 additions and 2 deletions

View File

@ -458,6 +458,7 @@ struct venus_inst {
bool next_buf_last; bool next_buf_last;
bool drain_active; bool drain_active;
enum venus_inst_modes flags; enum venus_inst_modes flags;
struct ida dpb_ids;
}; };
#define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX)

View File

@ -3,6 +3,7 @@
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd. * Copyright (C) 2017 Linaro Ltd.
*/ */
#include <linux/idr.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -21,6 +22,11 @@
#define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) #define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4))
#define NUM_MBS_4K (((ALIGN(4096, 16)) >> 4) * ((ALIGN(2304, 16)) >> 4)) #define NUM_MBS_4K (((ALIGN(4096, 16)) >> 4) * ((ALIGN(2304, 16)) >> 4))
enum dpb_buf_owner {
DRIVER,
FIRMWARE,
};
struct intbuf { struct intbuf {
struct list_head list; struct list_head list;
u32 type; u32 type;
@ -28,6 +34,8 @@ struct intbuf {
void *va; void *va;
dma_addr_t da; dma_addr_t da;
unsigned long attrs; unsigned long attrs;
enum dpb_buf_owner owned_by;
u32 dpb_out_tag;
}; };
bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt)
@ -95,9 +103,16 @@ int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
fdata.device_addr = buf->da; fdata.device_addr = buf->da;
fdata.buffer_type = buf->type; fdata.buffer_type = buf->type;
if (buf->owned_by == FIRMWARE)
continue;
fdata.clnt_data = buf->dpb_out_tag;
ret = hfi_session_process_buf(inst, &fdata); ret = hfi_session_process_buf(inst, &fdata);
if (ret) if (ret)
goto fail; goto fail;
buf->owned_by = FIRMWARE;
} }
fail: fail:
@ -110,13 +125,19 @@ int venus_helper_free_dpb_bufs(struct venus_inst *inst)
struct intbuf *buf, *n; struct intbuf *buf, *n;
list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) { list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) {
if (buf->owned_by == FIRMWARE)
continue;
ida_free(&inst->dpb_ids, buf->dpb_out_tag);
list_del_init(&buf->list); list_del_init(&buf->list);
dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
buf->attrs); buf->attrs);
kfree(buf); kfree(buf);
} }
INIT_LIST_HEAD(&inst->dpbbufs); if (list_empty(&inst->dpbbufs))
INIT_LIST_HEAD(&inst->dpbbufs);
return 0; return 0;
} }
@ -134,6 +155,7 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
unsigned int i; unsigned int i;
u32 count; u32 count;
int ret; int ret;
int id;
/* no need to allocate dpb buffers */ /* no need to allocate dpb buffers */
if (!inst->dpb_fmt) if (!inst->dpb_fmt)
@ -171,6 +193,15 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
buf->owned_by = DRIVER;
id = ida_alloc_min(&inst->dpb_ids, VB2_MAX_FRAME, GFP_KERNEL);
if (id < 0) {
ret = id;
goto fail;
}
buf->dpb_out_tag = id;
list_add_tail(&buf->list, &inst->dpbbufs); list_add_tail(&buf->list, &inst->dpbbufs);
} }
@ -1371,6 +1402,24 @@ venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx)
} }
EXPORT_SYMBOL_GPL(venus_helper_find_buf); EXPORT_SYMBOL_GPL(venus_helper_find_buf);
void venus_helper_change_dpb_owner(struct venus_inst *inst,
struct vb2_v4l2_buffer *vbuf, unsigned int type,
unsigned int buf_type, u32 tag)
{
struct intbuf *dpb_buf;
if (!V4L2_TYPE_IS_CAPTURE(type) ||
buf_type != inst->dpb_buftype)
return;
list_for_each_entry(dpb_buf, &inst->dpbbufs, list)
if (dpb_buf->dpb_out_tag == tag) {
dpb_buf->owned_by = DRIVER;
break;
}
}
EXPORT_SYMBOL_GPL(venus_helper_change_dpb_owner);
int venus_helper_vb2_buf_init(struct vb2_buffer *vb) int venus_helper_vb2_buf_init(struct vb2_buffer *vb)
{ {
struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);

View File

@ -14,6 +14,9 @@ struct venus_core;
bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt); bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt);
struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst,
unsigned int type, u32 idx); unsigned int type, u32 idx);
void venus_helper_change_dpb_owner(struct venus_inst *inst,
struct vb2_v4l2_buffer *vbuf, unsigned int type,
unsigned int buf_type, u32 idx);
void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type, void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type,
enum vb2_buffer_state state); enum vb2_buffer_state state);
int venus_helper_vb2_buf_init(struct vb2_buffer *vb); int venus_helper_vb2_buf_init(struct vb2_buffer *vb);

View File

@ -1339,8 +1339,10 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
vbuf = venus_helper_find_buf(inst, type, tag); vbuf = venus_helper_find_buf(inst, type, tag);
if (!vbuf) if (!vbuf) {
venus_helper_change_dpb_owner(inst, vbuf, type, buf_type, tag);
return; return;
}
vbuf->flags = flags; vbuf->flags = flags;
vbuf->field = V4L2_FIELD_NONE; vbuf->field = V4L2_FIELD_NONE;
@ -1622,6 +1624,8 @@ static int vdec_open(struct file *file)
vdec_inst_init(inst); vdec_inst_init(inst);
ida_init(&inst->dpb_ids);
/* /*
* create m2m device for every instance, the m2m context scheduling * create m2m device for every instance, the m2m context scheduling
* is made by firmware side so we do not need to care about. * is made by firmware side so we do not need to care about.
@ -1667,6 +1671,7 @@ static int vdec_close(struct file *file)
v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_ctx_release(inst->m2m_ctx);
v4l2_m2m_release(inst->m2m_dev); v4l2_m2m_release(inst->m2m_dev);
vdec_ctrl_deinit(inst); vdec_ctrl_deinit(inst);
ida_destroy(&inst->dpb_ids);
hfi_session_destroy(inst); hfi_session_destroy(inst);
mutex_destroy(&inst->lock); mutex_destroy(&inst->lock);
v4l2_fh_del(&inst->fh); v4l2_fh_del(&inst->fh);