From 22cc24de7f873b3047cbbdd3ede394c8a0a9f9bd Mon Sep 17 00:00:00 2001 From: Akshata Sahukar Date: Mon, 7 Feb 2022 11:45:56 -0800 Subject: [PATCH] video: driver: Enhance fence support - Introduce V4L2_EVENT_VIDC_METADATA to post fence fd returned in ETB metadata done buffer. - V4L2_CID_MPEG_VIDC_SW_FENCE_FD g_ctrl support for client to get fence fd for requested fence id. - Addition of fence delivery and subscribtion support. - Fence property packetization to send to firmware via FTB buffer. Change-Id: Ifb289849e352af2c4729aa95040bd83753979970 Signed-off-by: Akshata Sahukar --- driver/platform/kalama/src/msm_vidc_kalama.c | 19 ++- driver/vidc/inc/msm_vidc_driver.h | 4 +- driver/vidc/inc/msm_vidc_internal.h | 3 +- driver/vidc/src/msm_vdec.c | 113 ++++++++++++++++-- driver/vidc/src/msm_vidc_driver.c | 113 +++++++++++++++++- driver/vidc/src/msm_vidc_fence.c | 1 + driver/vidc/src/venus_hfi.c | 14 ++- driver/vidc/src/venus_hfi_response.c | 4 +- .../uapi/vidc/media/v4l2_vidc_extensions.h | 31 ++++- 9 files changed, 273 insertions(+), 29 deletions(-) diff --git a/driver/platform/kalama/src/msm_vidc_kalama.c b/driver/platform/kalama/src/msm_vidc_kalama.c index 0f6feada87..a6413e5691 100644 --- a/driver/platform/kalama/src/msm_vidc_kalama.c +++ b/driver/platform/kalama/src/msm_vidc_kalama.c @@ -277,18 +277,29 @@ static struct msm_platform_inst_capability instance_data_kalama[] = { {0}, NULL, msm_vidc_set_u32}, - {SW_FENCE_ENABLE, DEC, CODECS_ALL, + /* + * Client will enable V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {INPUT_META_OUTBUF_FENCE, DEC, CODECS_ALL, V4L2_MPEG_MSM_VIDC_DISABLE, V4L2_MPEG_MSM_VIDC_ENABLE, 1, V4L2_MPEG_MSM_VIDC_DISABLE, - V4L2_CID_MPEG_VIDC_SW_FENCE_ENABLE, + V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE, HFI_PROP_FENCE}, + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ {FENCE_ID, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, - V4L2_CID_MPEG_VIDC_SW_FENCE_ID}, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, {FENCE_FD, DEC, CODECS_ALL, - 0, INT_MAX, 1, 0, + INVALID_FD, INT_MAX, 1, INVALID_FD, V4L2_CID_MPEG_VIDC_SW_FENCE_FD}, {TS_REORDER, DEC, H264|HEVC, diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 3f80c8b066..05e9e028d3 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -298,8 +298,8 @@ int msm_vidc_alloc_and_queue_session_internal_buffers(struct msm_vidc_inst *inst enum msm_vidc_buffer_type buffer_type); int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buffer_type); -int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, - struct msm_vidc_buffer *buf); +int msm_vidc_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); int msm_vidc_remove_session(struct msm_vidc_inst *inst); int msm_vidc_add_session(struct msm_vidc_inst *inst); int msm_vidc_session_open(struct msm_vidc_inst *inst); diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 0698dc467f..645ae0414a 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -61,6 +61,7 @@ #define MAX_SUPPORTED_MIN_QUALITY 70 #define MIN_CHROMA_QP_OFFSET -12 #define MAX_CHROMA_QP_OFFSET 0 +#define INVALID_FD -1 #define DCVS_WINDOW 16 #define ENC_FPS_WINDOW 3 @@ -379,7 +380,7 @@ enum msm_vidc_inst_capability_type { MB_CYCLES_FW, MB_CYCLES_FW_VPP, SECURE_MODE, - SW_FENCE_ENABLE, + INPUT_META_OUTBUF_FENCE, FENCE_ID, FENCE_FD, TS_REORDER, diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index 141b61d45b..ffa866c2c5 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -77,6 +77,7 @@ static const u32 msm_vdec_output_subscribe_for_properties[] = { HFI_PROP_PICTURE_TYPE, HFI_PROP_DPB_LIST, HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, }; static const u32 msm_vdec_internal_buffer_type[] = { @@ -1230,6 +1231,8 @@ static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst, HFI_PAYLOAD_U32_ARRAY, &payload[0], (count + 1) * sizeof(u32)); + if (rc) + return rc; return rc; } @@ -1241,7 +1244,15 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, u32 payload[32] = {0}; u32 i, count = 0; struct msm_vidc_inst_capability *capability; - static const u32 metadata_list[] = { + const u32 metadata_input_list[] = { + INPUT_META_OUTBUF_FENCE, + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + META_OUTPUT_BUF_TAG, + }; + const u32 metadata_output_list[] = { META_BITSTREAM_RESOLUTION, META_CROP_OFFSETS, META_DPB_MISR, @@ -1253,6 +1264,9 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS, + /* + * client needs input buffer tag in output metadata buffer done. + */ META_BUF_TAG, META_DPB_TAG_LIST, META_SUBFRAME_OUTPUT, @@ -1268,14 +1282,28 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, capability = inst->capabilities; payload[0] = HFI_MODE_METADATA; - for (i = 0; i < ARRAY_SIZE(metadata_list); i++) { - if (capability->cap[metadata_list[i]].value && - msm_vidc_allow_metadata(inst, metadata_list[i])) { - payload[count + 1] = - capability->cap[metadata_list[i]].hfi_id; - count++; + if (port == INPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(metadata_input_list); i++) { + if (capability->cap[metadata_input_list[i]].value && + msm_vidc_allow_metadata(inst, metadata_input_list[i])) { + payload[count + 1] = + capability->cap[metadata_input_list[i]].hfi_id; + count++; + } } - }; + } else if (port == OUTPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(metadata_output_list); i++) { + if (capability->cap[metadata_output_list[i]].value && + msm_vidc_allow_metadata(inst, metadata_output_list[i])) { + payload[count + 1] = + capability->cap[metadata_output_list[i]].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } rc = venus_hfi_session_command(inst, HFI_CMD_SUBSCRIBE_MODE, @@ -1283,6 +1311,8 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, HFI_PAYLOAD_U32_ARRAY, &payload[0], (count + 1) * sizeof(u32)); + if (rc) + return rc; return rc; } @@ -1294,10 +1324,10 @@ static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst, u32 payload[32] = {0}; u32 i, count = 0; struct msm_vidc_inst_capability *capability; - static const u32 metadata_input_list[] = { + const u32 metadata_input_list[] = { META_BUF_TAG, }; - static const u32 metadata_output_list[] = { + const u32 metadata_output_list[] = { META_OUTPUT_BUF_TAG, }; @@ -1338,6 +1368,62 @@ static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst, HFI_PAYLOAD_U32_ARRAY, &payload[0], (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static int msm_vdec_set_delivery_mode_property(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + struct msm_vidc_inst_capability *capability; + const u32 property_output_list[] = { + INPUT_META_OUTBUF_FENCE, + }; + const u32 property_input_list[] = {}; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + i_vpr_h(inst, "%s()\n", __func__); + + capability = inst->capabilities; + payload[0] = HFI_MODE_PROPERTY; + + if (port == INPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(property_input_list); i++) { + if (capability->cap[property_input_list[i]].value) { + payload[count + 1] = + capability->cap[property_input_list[i]].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(property_output_list); i++) { + if (capability->cap[property_output_list[i]].value) { + payload[count + 1] = + capability->cap[property_output_list[i]].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_DELIVERY_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; return rc; } @@ -1354,6 +1440,8 @@ static int msm_vdec_session_resume(struct msm_vidc_inst *inst, HFI_PAYLOAD_NONE, NULL, 0); + if (rc) + return rc; return rc; } @@ -1984,6 +2072,10 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; + rc = msm_vdec_set_delivery_mode_property(inst, OUTPUT_PORT); + if (rc) + return rc; + rc = msm_vdec_set_delivery_mode_metadata(inst, OUTPUT_PORT); if (rc) return rc; @@ -2887,6 +2979,7 @@ int msm_vdec_subscribe_event(struct msm_vidc_inst *inst, switch (sub->type) { case V4L2_EVENT_EOS: + case V4L2_EVENT_VIDC_METADATA: rc = v4l2_event_subscribe(&inst->event_handler, sub, MAX_EVENTS, NULL); break; case V4L2_EVENT_SOURCE_CHANGE: diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index e84c7c99f2..6b2a51c4b0 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -82,7 +82,7 @@ static const struct msm_vidc_cap_name cap_name_arr[] = { {MB_CYCLES_FW, "MB_CYCLES_FW" }, {MB_CYCLES_FW_VPP, "MB_CYCLES_FW_VPP" }, {SECURE_MODE, "SECURE_MODE" }, - {SW_FENCE_ENABLE, "SW_FENCE_ENABLE" }, + {INPUT_META_OUTBUF_FENCE, "INPUT_META_OUTBUF_FENCE" }, {FENCE_ID, "FENCE_ID" }, {FENCE_FD, "FENCE_FD" }, {TS_REORDER, "TS_REORDER" }, @@ -1412,6 +1412,14 @@ bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id) is_allowed = false; } break; + case HFI_PROP_FENCE: + if (!inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value) { + i_vpr_h(inst, + "%s: cap: %24s not enabled, hence not allowed to subscribe\n", + __func__, cap_name(INPUT_META_OUTBUF_FENCE)); + is_allowed = false; + } + break; default: is_allowed = true; break; @@ -2016,6 +2024,46 @@ int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst) return rc; } +int msm_vidc_get_fence_fd(struct msm_vidc_inst *inst, int *fence_fd) +{ + int rc = 0; + struct msm_vidc_fence *fence, *dummy_fence; + bool found = false; + + *fence_fd = INVALID_FD; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { + if (fence->dma_fence.seqno == + (u64)inst->capabilities->cap[FENCE_ID].value) { + found = true; + break; + } + } + + if (!found) { + i_vpr_e(inst, "%s: could not find matching fence for fence id: %d\n", + __func__, inst->capabilities->cap[FENCE_ID].value); + rc = -EINVAL; + goto exit; + } + + if (fence->fd == INVALID_FD) { + rc = msm_vidc_create_fence_fd(inst, fence); + if (rc) + goto exit; + } + + *fence_fd = fence->fd; + +exit: + return rc; +} + int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) { int rc = 0; @@ -2041,6 +2089,12 @@ int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) i_vpr_h(inst, "%s: film grain present: %d\n", __func__, ctrl->val); break; + case V4L2_CID_MPEG_VIDC_SW_FENCE_FD: + rc = msm_vidc_get_fence_fd(inst, &ctrl->val); + if (!rc) + i_vpr_l(inst, "%s: fence fd: %d\n", + __func__, ctrl->val); + break; default: i_vpr_e(inst, "invalid ctrl %s id %d\n", ctrl->name, ctrl->id); @@ -3272,7 +3326,7 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer * if (!buf) return -EINVAL; - if (inst->capabilities->cap[SW_FENCE_ENABLE].value && + if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value && is_output_buffer(buf->type)) { fence = msm_vidc_fence_create(inst); if (!fence) @@ -3646,7 +3700,7 @@ int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst, return 0; } -int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, +static int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) { int type, port, state; @@ -3714,6 +3768,53 @@ int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, return 0; } +static int msm_vidc_v4l2_buffer_event(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct v4l2_event event = {0}; + struct v4l2_event_vidc_metadata *event_data = NULL; + + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (buf->type != MSM_VIDC_BUF_INPUT_META) { + i_vpr_e(inst, "%s: unsupported buffer type %s\n", + __func__, buf_name(buf->type)); + return -EINVAL; + } + + event.type = V4L2_EVENT_VIDC_METADATA; + event_data = (struct v4l2_event_vidc_metadata *)event.u.data; + event_data->type = INPUT_META_PLANE; + event_data->fd = buf->fd; + + v4l2_event_queue_fh(&inst->event_handler, &event); + + return rc; +} + +int msm_vidc_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + if (!inst || !inst->capabilities || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (buf->type == MSM_VIDC_BUF_INPUT_META && + inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) { + if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value) + return msm_vidc_v4l2_buffer_event(inst, buf); + } else { + return msm_vidc_vb2_buffer_done(inst, buf); + } + + return 0; +} + int msm_vidc_event_queue_init(struct msm_vidc_inst *inst) { int rc = 0; @@ -5086,7 +5187,7 @@ int msm_vidc_flush_buffers(struct msm_vidc_inst *inst, buf->attr & MSM_VIDC_ATTR_DEFERRED) { print_vidc_buffer(VIDC_HIGH, "high", "flushing buffer", inst, buf); if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) - msm_vidc_vb2_buffer_done(inst, buf); + msm_vidc_buffer_done(inst, buf); msm_vidc_put_driver_buf(inst, buf); } } @@ -5229,7 +5330,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); if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) - msm_vidc_vb2_buffer_done(inst, buf); + msm_vidc_buffer_done(inst, buf); msm_vidc_put_driver_buf(inst, buf); } msm_vidc_unmap_buffers(inst, ext_buf_types[i]); @@ -5267,7 +5368,7 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) } list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { - i_vpr_e(inst, "%s: destroying fence id: %llu", + i_vpr_e(inst, "%s: destroying fence id: %llu\n", __func__, fence->dma_fence.seqno); msm_vidc_fence_destroy(inst, fence); } diff --git a/driver/vidc/src/msm_vidc_fence.c b/driver/vidc/src/msm_vidc_fence.c index 6be30251e5..546578167c 100644 --- a/driver/vidc/src/msm_vidc_fence.c +++ b/driver/vidc/src/msm_vidc_fence.c @@ -63,6 +63,7 @@ struct msm_vidc_fence *msm_vidc_fence_create(struct msm_vidc_inst *inst) return NULL; } + fence->fd = INVALID_FD; spin_lock_init(&fence->lock); dma_fence_init(&fence->dma_fence, &msm_vidc_dma_fence_ops, &fence->lock, inst->fence_context.ctx_num, diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index f3886da9df..ebd82c96db 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -3523,9 +3523,19 @@ int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, goto unlock; } - if (inst->capabilities->cap[SW_FENCE_ENABLE].value && + if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value && is_output_buffer(buffer->type)) { - /* TODO(AS): create fence property packet to send to fw */ + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_PROP_FENCE, + 0, + HFI_PAYLOAD_U64, + HFI_PORT_RAW, + core->packet_id++, + &buffer->fence_id, + sizeof(u64)); + if (rc) + goto unlock; } rc = venus_hfi_add_pending_packets(inst); diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index f54bdbdaad..bc70fb53dd 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -1115,7 +1115,7 @@ static int handle_dequeue_buffers(struct msm_vidc_inst *inst) "vb2 done already", inst, buf); } else { buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE; - msm_vidc_vb2_buffer_done(inst, buf); + msm_vidc_buffer_done(inst, buf); } msm_vidc_put_driver_buf(inst, buf); } @@ -1557,7 +1557,7 @@ static int handle_session_property(struct msm_vidc_inst *inst, __func__, payload_ptr[0], inst->capabilities->cap[PIPE].value); break; case HFI_PROP_FENCE: - if (inst->capabilities->cap[SW_FENCE_ENABLE].value) { + if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value) { if (payload_ptr) { fence_id = payload_ptr[0]; rc = msm_vidc_fence_signal(inst, fence_id); diff --git a/include/uapi/vidc/media/v4l2_vidc_extensions.h b/include/uapi/vidc/media/v4l2_vidc_extensions.h index 7d64e8a4e1..555a72f88b 100644 --- a/include/uapi/vidc/media/v4l2_vidc_extensions.h +++ b/include/uapi/vidc/media/v4l2_vidc_extensions.h @@ -200,8 +200,8 @@ enum v4l2_mpeg_video_av1_tier { /* Control to enable input metadata via request api */ #define V4L2_CID_MPEG_VIDC_INPUT_METADATA_VIA_REQUEST_ENABLE \ (V4L2_CID_MPEG_VIDC_BASE + 0x37) -/* Control to enable software fence feature */ -#define V4L2_CID_MPEG_VIDC_SW_FENCE_ENABLE \ +/* Enables Output buffer fence id via input metadata */ +#define V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE \ (V4L2_CID_MPEG_VIDC_BASE + 0x38) /* Control to set fence id to driver in order get corresponding fence fd */ #define V4L2_CID_MPEG_VIDC_SW_FENCE_ID \ @@ -345,6 +345,7 @@ enum v4l2_mpeg_vidc_metadata { METADATA_ROI_INFO = 0x03000173, METADATA_DPB_TAG_LIST = 0x03000179, METADATA_MAX_NUM_REORDER_FRAMES = 0x03000127, + METADATA_FENCE = 0x0300018B, }; enum meta_interlace_info { META_INTERLACE_INFO_NONE = 0x00000000, @@ -358,4 +359,30 @@ enum meta_interlace_info { /* vendor controls end */ +/* vendor events start */ + +/* + * Vendor event structure looks like below (reference videodev2.h) + * struct v4l2_event { + * __u32 type; + * union { + * struct v4l2_event_src_change src_change; + * ... + * / ********** vendor event structure ******** / + * __u8 data[64]; + * } u; + * __u32 pending; + * ... + * } + */ +#define V4L2_EVENT_VIDC_METADATA \ + (V4L2_EVENT_PRIVATE_START + 0x1) + +struct v4l2_event_vidc_metadata { + __u32 type; + __s32 fd; + __u8 reserved[56]; +}; +/* vendor events end */ + #endif