Просмотр исходного кода

Merge "video: driver: new workhandler for inst events"

qctecmdr 4 лет назад
Родитель
Сommit
f6936f65e8

+ 15 - 0
driver/vidc/inc/msm_vidc_core.h

@@ -60,6 +60,18 @@ enum msm_vidc_core_state {
 	MSM_VIDC_CORE_ERROR        = 2,
 };
 
+enum work_type {
+	MSM_VIDC_INST_WORK_PSC = 1,
+};
+
+struct work_header {
+	void *data;
+	struct list_head list;
+	enum work_type type;
+	u32 session_id;
+	u32 data_size;
+};
+
 struct msm_vidc_core {
 	struct platform_device                *pdev;
 	struct msm_video_device                vdev[2];
@@ -108,6 +120,9 @@ struct msm_vidc_core {
 	u32                                    header_id;
 	u32                                    packet_id;
 	struct completion                      init_done;
+	struct list_head                       inst_works; /* list of struct work_header */
+	struct delayed_work                    inst_work;
+	struct workqueue_struct               *inst_workq;
 };
 
 #endif // _MSM_VIDC_CORE_H_

+ 2 - 0
driver/vidc/inc/msm_vidc_driver.h

@@ -179,6 +179,8 @@ int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type,
 	const char *func);
 int msm_vidc_change_inst_state(struct msm_vidc_inst *inst,
 	enum msm_vidc_inst_state state, const char *func);
+int msm_vidc_get_input_internal_buffers(struct msm_vidc_inst *inst,
+	enum msm_vidc_buffer_type buffer_type);
 int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
 		enum msm_vidc_buffer_type buffer_type);
 int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst,

+ 1 - 0
driver/vidc/inc/msm_vidc_internal.h

@@ -705,6 +705,7 @@ struct msm_vidc_buffers {
 	u32                    extra_count;
 	u32                    actual_count;
 	u32                    size;
+	bool                   reuse;
 };
 
 struct msm_vidc_ssr {

+ 1 - 0
driver/vidc/inc/venus_hfi.h

@@ -71,6 +71,7 @@ int venus_hfi_scale_buses(struct msm_vidc_inst* inst, u64 bw_ddr, u64 bw_llcc);
 
 void venus_hfi_work_handler(struct work_struct *work);
 void venus_hfi_pm_work_handler(struct work_struct *work);
+void venus_hfi_inst_work_handler(struct work_struct *work);
 irqreturn_t venus_hfi_isr(int irq, void *data);
 
 void __write_register(struct msm_vidc_core *core,

+ 37 - 41
driver/vidc/src/msm_vdec.c

@@ -725,56 +725,53 @@ static int msm_vdec_set_output_properties(struct msm_vidc_inst *inst)
 static int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	struct msm_vidc_core *core;
 
-	if (!inst || !inst->core) {
+	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
-	core = inst->core;
 
-	/*
-	 * TODO: Remove the hack of sending bigger buffer sizes
-	 * once internal buffer calculations are finalised
-	 */
-	inst->buffers.bin.size = call_session_op(core, buffer_size,
-			inst, MSM_VIDC_BUF_BIN) + 100000000;
-	inst->buffers.comv.size = call_session_op(core, buffer_size,
-			inst, MSM_VIDC_BUF_COMV) + 100000000;
-	inst->buffers.non_comv.size = call_session_op(core, buffer_size,
-			inst, MSM_VIDC_BUF_NON_COMV) + 100000000;
-	inst->buffers.line.size = call_session_op(core, buffer_size,
-			inst, MSM_VIDC_BUF_LINE) + 100000000;
-	inst->buffers.persist.size = call_session_op(core, buffer_size,
-			inst, MSM_VIDC_BUF_PERSIST) + 100000000;
-
-	inst->buffers.bin.min_count = call_session_op(core, min_count,
-			inst, MSM_VIDC_BUF_BIN);
-	inst->buffers.comv.min_count = call_session_op(core, min_count,
-			inst, MSM_VIDC_BUF_COMV);
-	inst->buffers.non_comv.min_count = call_session_op(core, min_count,
-			inst, MSM_VIDC_BUF_NON_COMV);
-	inst->buffers.line.min_count = call_session_op(core, min_count,
-			inst, MSM_VIDC_BUF_LINE);
-	inst->buffers.persist.min_count = call_session_op(core, min_count,
-			inst, MSM_VIDC_BUF_PERSIST);
-
-	s_vpr_h(inst->sid, "internal buffer: min     size\n");
-	s_vpr_h(inst->sid, "bin  buffer: %d      %d\n",
+	rc = msm_vidc_get_input_internal_buffers(inst, MSM_VIDC_BUF_BIN);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_get_input_internal_buffers(inst, MSM_VIDC_BUF_COMV);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_get_input_internal_buffers(inst, MSM_VIDC_BUF_NON_COMV);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_get_input_internal_buffers(inst, MSM_VIDC_BUF_LINE);
+	if (rc)
+		return rc;
+
+	rc = msm_vidc_get_input_internal_buffers(inst, MSM_VIDC_BUF_PERSIST);
+	if (rc)
+		return rc;
+
+	s_vpr_h(inst->sid, "internal buffer: min     size     reuse\n");
+	s_vpr_h(inst->sid, "bin  buffer: %d      %d      %d\n",
 		inst->buffers.bin.min_count,
-		inst->buffers.bin.size);
-	s_vpr_h(inst->sid, "comv  buffer: %d      %d\n",
+		inst->buffers.bin.size,
+		inst->buffers.bin.reuse);
+	s_vpr_h(inst->sid, "comv  buffer: %d      %d      %d\n",
 		inst->buffers.comv.min_count,
-		inst->buffers.comv.size);
-	s_vpr_h(inst->sid, "non_comv  buffer: %d      %d\n",
+		inst->buffers.comv.size,
+		inst->buffers.comv.reuse);
+	s_vpr_h(inst->sid, "non_comv  buffer: %d      %d      %d\n",
 		inst->buffers.non_comv.min_count,
-		inst->buffers.non_comv.size);
-	s_vpr_h(inst->sid, "line buffer: %d      %d\n",
+		inst->buffers.non_comv.size,
+		inst->buffers.non_comv.reuse);
+	s_vpr_h(inst->sid, "line buffer: %d      %d      %d\n",
 		inst->buffers.line.min_count,
-		inst->buffers.line.size);
-	s_vpr_h(inst->sid, "persist buffer: %d      %d\n",
+		inst->buffers.line.size,
+		inst->buffers.line.reuse);
+	s_vpr_h(inst->sid, "buffer: %d      %d      %d\n",
 		inst->buffers.persist.min_count,
-		inst->buffers.persist.size);
+		inst->buffers.persist.size,
+		inst->buffers.persist.reuse);
 
 	return rc;
 }
@@ -1853,4 +1850,3 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst)
 
 	return rc;
 }
-

+ 57 - 0
driver/vidc/src/msm_vidc_driver.c

@@ -916,6 +916,45 @@ int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst,
 	return 0;
 }
 
+int msm_vidc_get_input_internal_buffers(struct msm_vidc_inst *inst,
+	enum msm_vidc_buffer_type buffer_type)
+{
+	u32 buf_size;
+	u32 buf_count;
+	struct msm_vidc_core *core;
+	struct msm_vidc_buffers *buffers;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	/*
+	 * TODO: Remove the hack of sending bigger buffer sizes
+	 * once internal buffer calculations are finalised
+	 */
+	buf_size = call_session_op(core, buffer_size,
+		inst, buffer_type) + 100000000;
+
+	buf_count = call_session_op(core, min_count,
+		inst, buffer_type);
+
+	buffers = msm_vidc_get_buffers(inst, buffer_type, __func__);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buf_size <= buffers->size &&
+		buf_count <= buffers->min_count) {
+		buffers->reuse = true;
+	} else {
+		buffers->reuse = false;
+		buffers->size = buf_size;
+		buffers->min_count = buf_count;
+	}
+	return 0;
+}
+
 int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type, u32 index)
 {
@@ -1022,6 +1061,12 @@ int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
 	if (!buffers)
 		return -EINVAL;
 
+	if (buffers->reuse) {
+		s_vpr_l(inst->sid, "%s: reuse enabled for buffer type %#x\n",
+			__func__, buffer_type);
+		return 0;
+	}
+
 	for (i = 0; i < buffers->min_count; i++)
 		rc = msm_vidc_create_internal_buffer(inst, buffer_type, i);
 
@@ -1050,6 +1095,12 @@ int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst,
 	if (!buffers)
 		return -EINVAL;
 
+	if (buffers->reuse) {
+		s_vpr_l(inst->sid, "%s: reuse enabled for buffer type %#x\n",
+			__func__, buffer_type);
+		return 0;
+	}
+
 	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
 		/* do not queue pending release buffers */
 		if (buffer->flags & MSM_VIDC_ATTR_PENDING_RELEASE)
@@ -1092,6 +1143,12 @@ int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
 	if (!buffers)
 		return -EINVAL;
 
+	if (buffers->reuse) {
+		s_vpr_l(inst->sid, "%s: reuse enabled for buffer type %#x\n",
+			__func__, buffer_type);
+		return 0;
+	}
+
 	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
 		/* do not release already pending release buffers */
 		if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE)

+ 10 - 0
driver/vidc/src/msm_vidc_probe.c

@@ -214,15 +214,25 @@ static int msm_vidc_initialize_core(struct msm_vidc_core *core)
 		goto exit;
 	}
 
+	core->inst_workq = create_singlethread_workqueue("inst_workq");
+	if (!core->inst_workq) {
+		d_vpr_e("%s: create workq failed\n", __func__);
+		destroy_workqueue(core->inst_workq);
+		rc = -EINVAL;
+		goto exit;
+	}
+
 	mutex_init(&core->lock);
 	INIT_LIST_HEAD(&core->instances);
 	INIT_LIST_HEAD(&core->dangling_instances);
+	INIT_LIST_HEAD(&core->inst_works);
 
 	INIT_WORK(&core->device_work, venus_hfi_work_handler);
 	INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
 	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
 	INIT_DELAYED_WORK(&core->batch_work, msm_vidc_batch_handler);
 	INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler);
+	INIT_DELAYED_WORK(&core->inst_work, venus_hfi_inst_work_handler);
 
 exit:
 	return rc;

+ 140 - 9
driver/vidc/src/venus_hfi_response.c

@@ -124,8 +124,7 @@ int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
 		return -EINVAL;
 	}
 
-	response_limit = core_resp_pkt + core_resp_pkt_size -
-		max(sizeof(struct hfi_header), sizeof(struct hfi_packet));
+	response_limit = core_resp_pkt + core_resp_pkt_size;
 
 	if (response_pkt < core_resp_pkt || response_pkt > response_limit) {
 		d_vpr_e("%s: invalid packet address\n", func);
@@ -963,6 +962,121 @@ exit:
 	return rc;
 }
 
+static int venus_hfi_input_psc(struct msm_vidc_core *core,
+	struct work_header *work_hdr)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hfi_header *hdr = NULL;
+	struct hfi_packet *packet;
+	u8 *pkt, *temp_pkt;
+	u32 hfi_cmd_type = 0;
+	u32 hfi_port = 0;
+	int i;
+
+	if (!work_hdr) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct hfi_header *)work_hdr->data;
+	if (!hdr) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = get_inst(core, hdr->session_id);
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->lock);
+	hfi_cmd_type = 0;
+	hfi_port = 0;
+	pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header));
+	temp_pkt = pkt;
+
+	for (i = 0; i < hdr->num_packets; i++) {
+		if (validate_packet(pkt, work_hdr->data,
+				work_hdr->data_size, __func__)) {
+			rc = -EINVAL;
+			goto exit;
+		}
+		packet = (struct hfi_packet *)pkt;
+		if (packet->type > HFI_CMD_BEGIN &&
+			packet->type < HFI_CMD_END) {
+			if (hfi_cmd_type == HFI_CMD_SETTINGS_CHANGE) {
+				s_vpr_e(inst->sid,
+					"%s: invalid packet type %d in port settings change\n",
+					__func__, packet->type);
+				rc = -EINVAL;
+				goto exit;
+			}
+			hfi_cmd_type = packet->type;
+			hfi_port = packet->port;
+			rc = handle_session_command(inst, packet);
+		} else if (packet->type > HFI_PROP_BEGIN &&
+			packet->type < HFI_PROP_END) {
+			rc = handle_session_property(inst, packet);
+		} else if (packet->type > HFI_SESSION_ERROR_BEGIN &&
+			packet->type < HFI_SESSION_ERROR_END) {
+			rc = handle_session_error(inst, packet);
+		} else if (packet->type > HFI_INFORMATION_BEGIN &&
+			packet->type < HFI_INFORMATION_END) {
+			rc = handle_session_info(inst, packet);
+		} else {
+			s_vpr_e(inst->sid, "%s: Unknown packet type: %#x\n",
+				__func__, packet->type);
+			rc = -EINVAL;
+			goto exit;
+		}
+		pkt += packet->size;
+	}
+
+	if (hfi_cmd_type == HFI_CMD_SETTINGS_CHANGE) {
+		if (hfi_port == HFI_PORT_BITSTREAM) {
+			print_psc_properties(VIDC_HIGH, "INPUT_PSC", inst,
+				inst->subcr_params[INPUT_PORT]);
+			rc = msm_vdec_input_port_settings_change(inst);
+			if (rc)
+				goto exit;
+		}
+	}
+
+exit:
+	mutex_unlock(&inst->lock);
+	put_inst(inst);
+	return rc;
+}
+
+void venus_hfi_inst_work_handler(struct work_struct *work)
+{
+	struct msm_vidc_core *core;
+	struct work_header *work_hdr, *dummy = NULL;
+
+	core = container_of(work, struct msm_vidc_core, inst_work.work);
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	list_for_each_entry_safe(work_hdr, dummy, &core->inst_works, list) {
+		switch (work_hdr->type) {
+		case MSM_VIDC_INST_WORK_PSC:
+			venus_hfi_input_psc(core, work_hdr);
+			break;
+		default:
+			d_vpr_e("%s(): invalid work type: %d\n", __func__,
+				work_hdr->type);
+			break;
+		}
+		list_del(&work_hdr->list);
+		kfree(work_hdr->data);
+		kfree(work_hdr);
+	}
+}
+
 static int handle_session_response(struct msm_vidc_core *core,
 	struct hfi_header *hdr)
 {
@@ -994,6 +1108,26 @@ static int handle_session_response(struct msm_vidc_core *core,
 		packet = (struct hfi_packet *)pkt;
 		if (packet->type > HFI_CMD_BEGIN &&
 		    packet->type < HFI_CMD_END) {
+			if (packet->type == HFI_CMD_SETTINGS_CHANGE &&
+				packet->port == HFI_PORT_BITSTREAM) {
+				struct work_header *work;
+
+				work = kzalloc(sizeof(struct work_header), GFP_KERNEL);
+				INIT_LIST_HEAD(&work->list);
+				work->type = MSM_VIDC_INST_WORK_PSC;
+				work->session_id = hdr->session_id;
+				work->data_size = hdr->size;
+				work->data = kzalloc(hdr->size, GFP_KERNEL);
+				if (!work->data) {
+					rc= -ENOMEM;
+					goto exit;
+				}
+				memcpy(work->data, (void *)hdr, hdr->size);
+				list_add_tail(&work->list, &core->inst_works);
+				queue_delayed_work(core->inst_workq,
+					&core->inst_work, msecs_to_jiffies(0));
+				goto exit;
+			}
 			if (hfi_cmd_type == HFI_CMD_SETTINGS_CHANGE) {
 				s_vpr_e(inst->sid,
 					"%s: invalid packet type %d in port settings change\n",
@@ -1029,18 +1163,15 @@ static int handle_session_response(struct msm_vidc_core *core,
 	}
 
 	if (hfi_cmd_type == HFI_CMD_SETTINGS_CHANGE) {
-		if (hfi_port == HFI_PORT_BITSTREAM) {
-			print_psc_properties(VIDC_HIGH, "INPUT_PSC", inst,
-				inst->subcr_params[INPUT_PORT]);
-			rc = msm_vdec_input_port_settings_change(inst);
-			if (rc)
-				goto exit;
-		} else if (hfi_port == HFI_PORT_RAW) {
+		if (hfi_port == HFI_PORT_RAW) {
 			print_psc_properties(VIDC_HIGH, "OUTPUT_PSC", inst,
 				inst->subcr_params[OUTPUT_PORT]);
 			rc = msm_vdec_output_port_settings_change(inst);
 			if (rc)
 				goto exit;
+		} else {
+			s_vpr_e(inst->sid, "%s: invalid port type: %#x\n",
+				__func__, hfi_port);
 		}
 	}