Przeglądaj źródła

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 <[email protected]>
Akshata Sahukar 3 lat temu
rodzic
commit
22cc24de7f

+ 15 - 4
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,

+ 2 - 2
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);

+ 2 - 1
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,

+ 103 - 10
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:

+ 107 - 6
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);
 	}

+ 1 - 0
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,

+ 12 - 2
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);

+ 2 - 2
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);

+ 29 - 2
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