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

Commit 6d34f202 authored by Deva Ramasubramanian's avatar Deva Ramasubramanian
Browse files

msm: vidc: Handle hfi session creation failures properly



Previously, when the hfi session creation failed, the hfi session was
left intact.  So in case of timeouts, if the core responded beyond the
time out, the driver would handle the message thinking that it's a valid
session.  This commit cleans up the hfi session in case session_init
fails (or times out).

Also rename msm_comm_recover_from_session_error to msm_comm_kill_session,
as the latter was a misnomer, as the function was used to abort a session.

CRs-Fixed: 624386
Change-Id: I9ec4337014f012b6c0f677c5c4844bf9b28c9899
Signed-off-by: default avatarDeva Ramasubramanian <dramasub@codeaurora.org>
parent 5d2fc27d
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,