Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 108c530b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: vidc: Handle hfi session creation failures properly"

parents 5ad178a9 6d34f202
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1657,7 +1657,7 @@ int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
	case V4L2_DEC_QCOM_CMD_FLUSH:
	case V4L2_DEC_QCOM_CMD_FLUSH:
		if (core->state != VIDC_CORE_INVALID &&
		if (core->state != VIDC_CORE_INVALID &&
			inst->state ==  MSM_VIDC_CORE_INVALID) {
			inst->state ==  MSM_VIDC_CORE_INVALID) {
			rc = msm_comm_recover_from_session_error(inst);
			rc = msm_comm_kill_session(inst);
			if (rc)
			if (rc)
				dprintk(VIDC_ERR,
				dprintk(VIDC_ERR,
					"Failed to recover from session_error: %d\n",
					"Failed to recover from session_error: %d\n",
@@ -1672,7 +1672,7 @@ int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
	case V4L2_DEC_CMD_STOP:
	case V4L2_DEC_CMD_STOP:
		if (core->state != VIDC_CORE_INVALID &&
		if (core->state != VIDC_CORE_INVALID &&
			inst->state ==  MSM_VIDC_CORE_INVALID) {
			inst->state ==  MSM_VIDC_CORE_INVALID) {
			rc = msm_comm_recover_from_session_error(inst);
			rc = msm_comm_kill_session(inst);
			if (rc)
			if (rc)
				dprintk(VIDC_ERR,
				dprintk(VIDC_ERR,
					"Failed to recover from session_error: %d\n",
					"Failed to recover from session_error: %d\n",
+93 −60
Original line number Original line Diff line number Diff line
@@ -42,6 +42,9 @@ struct getprop_buf {
	void *data;
	void *data;
};
};


static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);

static inline bool is_turbo_session(struct msm_vidc_inst *inst)
static inline bool is_turbo_session(struct msm_vidc_inst *inst)
{
{
	return !!(inst->flags & VIDC_TURBO);
	return !!(inst->flags & VIDC_TURBO);
@@ -494,7 +497,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
		dprintk(VIDC_ERR,
		dprintk(VIDC_ERR,
			"%s: Wait interrupted or timed out [%p]: %d\n",
			"%s: Wait interrupted or timed out [%p]: %d\n",
			__func__, inst, SESSION_MSG_INDEX(cmd));
			__func__, inst, SESSION_MSG_INDEX(cmd));
		msm_comm_recover_from_session_error(inst);
		msm_comm_kill_session(inst);
		rc = -EIO;
		rc = -EIO;
	} else {
	} else {
		rc = 0;
		rc = 0;
@@ -528,19 +531,6 @@ void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
	wake_up(&inst->kernel_event_queue);
	wake_up(&inst->kernel_event_queue);
}
}


static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
{
	if (!inst) {
		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
		return;
	}
	mutex_lock(&inst->lock);
	inst->session = NULL;
	inst->state = MSM_VIDC_CORE_INVALID;
	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
	mutex_unlock(&inst->lock);
}

static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
{
{
	if (!inst) {
	if (!inst) {
@@ -865,22 +855,40 @@ static void handle_session_flush(enum command_response cmd, void *data)
static void handle_session_error(enum command_response cmd, void *data)
static void handle_session_error(enum command_response cmd, void *data)
{
{
	struct msm_vidc_cb_cmd_done *response = data;
	struct msm_vidc_cb_cmd_done *response = data;
	int rc;
	struct hfi_device *hdev = NULL;
	struct msm_vidc_inst *inst = NULL;
	struct msm_vidc_inst *inst = NULL;
	if (response) {

	if (!response) {
		dprintk(VIDC_ERR,
			"Failed to get valid response for session error\n");
		return;
	}

	inst = (struct msm_vidc_inst *)response->session_id;
	inst = (struct msm_vidc_inst *)response->session_id;
		if (inst) {

			dprintk(VIDC_WARN,
	if (!inst || !inst->session || !inst->core->device) {
				"Session error receivd for session %p\n", inst);
		dprintk(VIDC_ERR,
				"Session (%p) not in a stable enough state to handle session error\n",
				inst);
		return;
	}

	hdev = inst->core->device;
	dprintk(VIDC_WARN, "Session error received for session %p\n", inst);

	mutex_lock(&inst->sync_lock);
	mutex_lock(&inst->sync_lock);
	inst->state = MSM_VIDC_CORE_INVALID;
	inst->state = MSM_VIDC_CORE_INVALID;

	dprintk(VIDC_DBG, "cleaning up inst: %p\n", inst);
	rc = call_hfi_op(hdev, session_clean, inst->session);
	if (rc)
		dprintk(VIDC_ERR, "Session (%p) clean failed: %d\n", inst, rc);

	inst->session = NULL;
	mutex_unlock(&inst->sync_lock);
	mutex_unlock(&inst->sync_lock);
			msm_vidc_queue_v4l2_event(inst,

					V4L2_EVENT_MSM_VIDC_SYS_ERROR);
	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
		}
	} else {
		dprintk(VIDC_ERR,
			"Failed to get valid response for session error\n");
	}
}
}
static void handle_sys_error(enum command_response cmd, void *data)
static void handle_sys_error(enum command_response cmd, void *data)
{
{
@@ -1259,10 +1267,10 @@ static void handle_fbd(enum command_response cmd, void *data)
	inst = (struct msm_vidc_inst *)response->session_id;
	inst = (struct msm_vidc_inst *)response->session_id;
	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
	buffer_type = msm_comm_get_hal_output_buffer(inst);
	buffer_type = msm_comm_get_hal_output_buffer(inst);
	if (fill_buf_done->buffer_type == buffer_type)
	if (fill_buf_done->buffer_type == buffer_type) {
		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
				fill_buf_done->packet_buffer1);
				fill_buf_done->packet_buffer1);
	else {
	} else {
		if (handle_multi_stream_buffers(inst,
		if (handle_multi_stream_buffers(inst,
				fill_buf_done->packet_buffer1))
				fill_buf_done->packet_buffer1))
			dprintk(VIDC_ERR,
			dprintk(VIDC_ERR,
@@ -1825,7 +1833,7 @@ static int msm_vidc_load_resources(int flipped_state,
		inst->state = MSM_VIDC_CORE_INVALID;
		inst->state = MSM_VIDC_CORE_INVALID;
		msm_vidc_queue_v4l2_event(inst,
		msm_vidc_queue_v4l2_event(inst,
					V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
					V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
		msm_comm_recover_from_session_error(inst);
		msm_comm_kill_session(inst);
		return -ENOMEM;
		return -ENOMEM;
	}
	}


@@ -2696,7 +2704,7 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
			__func__, inst,
			__func__, inst,
			SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
			SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
		inst->state = MSM_VIDC_CORE_INVALID;
		inst->state = MSM_VIDC_CORE_INVALID;
		msm_comm_recover_from_session_error(inst);
		msm_comm_kill_session(inst);
		rc = -EIO;
		rc = -EIO;
		goto exit;
		goto exit;
	}
	}
@@ -2830,8 +2838,7 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
					mutex_lock(&inst->sync_lock);
					mutex_lock(&inst->sync_lock);
					inst->state = MSM_VIDC_CORE_INVALID;
					inst->state = MSM_VIDC_CORE_INVALID;
					mutex_unlock(&inst->sync_lock);
					mutex_unlock(&inst->sync_lock);
					msm_comm_recover_from_session_error(
					msm_comm_kill_session(inst);
						inst);
				}
				}
				mutex_lock(&inst->lock);
				mutex_lock(&inst->lock);
			}
			}
@@ -2901,8 +2908,7 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
					mutex_lock(&inst->sync_lock);
					mutex_lock(&inst->sync_lock);
					inst->state = MSM_VIDC_CORE_INVALID;
					inst->state = MSM_VIDC_CORE_INVALID;
					mutex_unlock(&inst->sync_lock);
					mutex_unlock(&inst->sync_lock);
					msm_comm_recover_from_session_error(
					msm_comm_kill_session(inst);
						inst);
				}
				}
				mutex_lock(&inst->lock);
				mutex_lock(&inst->lock);
			}
			}
@@ -3511,6 +3517,20 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
	return rc;
	return rc;
}
}


static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
{
	enum command_response cmd = SESSION_ERROR;
	struct msm_vidc_cb_cmd_done response = {0};

	if (!inst || !inst->core) {
		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
		return;
	}

	response.session_id = inst;
	handle_session_error(cmd, (void *)&response);
}

static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
{
{
	struct msm_vidc_core *core;
	struct msm_vidc_core *core;
@@ -3525,42 +3545,55 @@ static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
	handle_sys_error(cmd, (void *) &response);
	handle_sys_error(cmd, (void *) &response);


}
}
int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)

int msm_comm_kill_session(struct msm_vidc_inst *inst)
{
{
	struct hfi_device *hdev;
	int rc = 0;
	int rc = 0;


	if (!inst || !inst->core || !inst->core->device) {
	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
		return -EINVAL;
		return -EINVAL;
	} else if (!inst->session) {
		/* There's no hfi session to kill */
		return 0;
	}
	}
	if (!inst->session || inst->state < MSM_VIDC_OPEN_DONE) {
		dprintk(VIDC_WARN,
			"No corresponding FW session. No need to send Abort\n");
		return rc;
	}
	hdev = inst->core->device;


	init_completion(&inst->completions[SESSION_MSG_INDEX
	/*
		(SESSION_ABORT_DONE)]);
	 * We're internally forcibly killing the session, if fw is aware of

	 * the session send session_abort to firmware to clean up and release
	/* We have received session_error. Send session_abort to firmware
	 * the session, else just kill the session inside the driver.
	 *  to clean up and release the session
	 */
	 */
	if (inst->state >= MSM_VIDC_OPEN_DONE ||
			inst->state < MSM_VIDC_CLOSE_DONE) {
		struct hfi_device *hdev = inst->core->device;
		int abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE);

		rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
		rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
		if (rc) {
		if (rc) {
			dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
			dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
			return rc;
			return rc;
		}
		}

		init_completion(&inst->completions[abort_completion]);
		rc = wait_for_completion_timeout(
		rc = wait_for_completion_timeout(
		&inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
				&inst->completions[abort_completion],
				msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
				msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
		if (!rc) {
		if (!rc) {
		dprintk(VIDC_ERR, "%s: Wait interrupted or timed out [%p]:%d\n",
			dprintk(VIDC_ERR,
			__func__, inst, SESSION_MSG_INDEX(SESSION_ABORT_DONE));
					"%s: Wait interrupted or timed out [%p]: %d\n",
					__func__, inst, abort_completion);
			msm_comm_generate_sys_error(inst);
			msm_comm_generate_sys_error(inst);
	} else
		} else {
			change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
			change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
		}
	} else {
		dprintk(VIDC_WARN,
				"Inactive session %p, triggering an internal session error\n",
				inst);
		msm_comm_generate_session_error(inst);

	}

	return rc;
	return rc;
}
}


+2 −2
Original line number Original line Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * it under the terms of the GNU General Public License version 2 and
@@ -52,7 +52,7 @@ struct hal_buffer_requirements *get_buff_req_buffer(
		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
		V4L2_CTRL_DRIVER_PRIV(idx))
		V4L2_CTRL_DRIVER_PRIV(idx))


int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
int msm_comm_kill_session(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,