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

Commit 38dc7fd0 authored by Maheshwar Ajja's avatar Maheshwar Ajja
Browse files

msm: vidc: Handle max clients error from video hardware



Use instance "lock" instead of "sync_lock" variable for
mutex lock/unlock for video instance state change operation
else session init will be timed out due to dead lock when
max clients error is received from video hardware because
"sync_lock" is already acquired before session init.
At the same time do not free the session when any error
is received from video hardware, if freed results in
dangling pointer access when video driver wants to send
any commands to video hardware after session error,
leading to device reset. The proper way of session cleanup
is already being done upon receiving any errors from
video hardware.

CRs-Fixed: 653087
Change-Id: I689dd255681826508069fa86fb5a87f92fc775b5
Signed-off-by: default avatarMaheshwar Ajja <majja@codeaurora.org>
parent 2a00eb3a
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ static void hfi_process_session_error(
	struct msm_vidc_cb_cmd_done cmd_done = {0};
	cmd_done.device_id = device_id;
	cmd_done.session_id = session->session_id;
	cmd_done.status = hfi_map_err_status(pkt->event_data1);
	dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
		pkt->event_data1);
	switch (pkt->event_data1) {
@@ -229,6 +230,7 @@ static void hfi_process_session_error(
	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
		cmd_done.status = VIDC_ERR_NONE;
		dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
		break;
	default:
@@ -899,11 +901,9 @@ static void hfi_process_session_init_done(
		cmd_done.status = hfi_process_sess_init_done_prop_read(
			pkt, &session_init_done);
	} else if (session) {
		dprintk(VIDC_INFO,
			"Sess init failed: Deleting session: 0x%p 0x%p\n",
		dprintk(VIDC_WARN,
			"Sess init failed: 0x%p, 0x%p\n",
			session->session_id, session);
		list_del(&session->list);
		kfree(session);
	}
	cmd_done.size = sizeof(struct vidc_hal_session_init_done);
	callback(SESSION_INIT_DONE, &cmd_done);
+32 −22
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ struct getprop_buf {

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 void handle_session_error(enum command_response cmd, void *data);

static inline bool is_turbo_session(struct msm_vidc_inst *inst)
{
@@ -551,17 +552,17 @@ void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)

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

	if (!inst) {
		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
		return;
	}
	mutex_lock(&inst->sync_lock);
	inst->session = NULL;
	inst->state = MSM_VIDC_CORE_INVALID;
	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
	dprintk(VIDC_ERR,
			"%s: Too many clients\n", __func__);
	mutex_unlock(&inst->sync_lock);
	dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
	response.session_id = inst;
	response.status = VIDC_ERR_MAX_CLIENTS;
	handle_session_error(cmd, (void *)&response);
}

static void handle_session_init_done(enum command_response cmd, void *data)
@@ -963,19 +964,30 @@ static void handle_session_error(enum command_response cmd, void *data)

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

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

	mutex_lock(&inst->lock);
	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->lock);

	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
	if (response->status == VIDC_ERR_MAX_CLIENTS) {
		dprintk(VIDC_WARN,
			"send max clients reached error to client: %p\n",
			inst);
		msm_vidc_queue_v4l2_event(inst,
			V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
	} else {
		dprintk(VIDC_ERR,
			"send session error to client: %p\n",
			inst);
		msm_vidc_queue_v4l2_event(inst,
			V4L2_EVENT_MSM_VIDC_SYS_ERROR);
	}
}

struct sys_err_handler_data {
@@ -2986,9 +2998,8 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
				rc = wait_for_sess_signal_receipt(inst,
					SESSION_RELEASE_BUFFER_DONE);
				if (rc) {
					mutex_lock(&inst->sync_lock);
					inst->state = MSM_VIDC_CORE_INVALID;
					mutex_unlock(&inst->sync_lock);
					change_inst_state(inst,
						MSM_VIDC_CORE_INVALID);
					msm_comm_kill_session(inst);
				}
				mutex_lock(&inst->lock);
@@ -3056,9 +3067,8 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
				rc = wait_for_sess_signal_receipt(inst,
					SESSION_RELEASE_BUFFER_DONE);
				if (rc) {
					mutex_lock(&inst->sync_lock);
					inst->state = MSM_VIDC_CORE_INVALID;
					mutex_unlock(&inst->sync_lock);
					change_inst_state(inst,
						MSM_VIDC_CORE_INVALID);
					msm_comm_kill_session(inst);
				}
				mutex_lock(&inst->lock);
@@ -3658,9 +3668,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
		}
	}
	if (rc) {
		mutex_lock(&inst->sync_lock);
		inst->state = MSM_VIDC_CORE_INVALID;
		mutex_unlock(&inst->sync_lock);
		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
		msm_vidc_queue_v4l2_event(inst,
					V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
		dprintk(VIDC_WARN,
@@ -3674,12 +3682,14 @@ 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};

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

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

@@ -3715,7 +3725,7 @@ int msm_comm_kill_session(struct msm_vidc_inst *inst)
	 * the session send session_abort to firmware to clean up and release
	 * the session, else just kill the session inside the driver.
	 */
	if (inst->state >= MSM_VIDC_OPEN_DONE ||
	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);