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

Commit 12d908fe authored by Jayant Shekhar's avatar Jayant Shekhar
Browse files

drm/msm/sde: Fix NOC error in vsync handler



There are cases where MDP clocks switches off and then
mod timer triggers vsync handler where auto refresh config
register is accessed with clock disabled. This results in
NOC error and then resulting in system crash. Fix the issue
by adding resource control while accessing the auto refresh
config register.

Change-Id: I742775d32bf422c8a073d86530a36b724f16486f
Signed-off-by: default avatarJayant Shekhar <jshekhar@codeaurora.org>
parent 099e9fc7
Loading
Loading
Loading
Loading
+24 −17
Original line number Diff line number Diff line
@@ -1762,8 +1762,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
		break;

	case SDE_ENC_RC_EVENT_STOP:
		mutex_lock(&sde_enc->rc_lock);
		/* cancel vsync event work */
		kthread_cancel_work_sync(&sde_enc->vsync_event_work);

		mutex_lock(&sde_enc->rc_lock);
		/* return if the resource control is already in OFF state */
		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
@@ -2948,7 +2950,6 @@ static void sde_encoder_vsync_event_handler(unsigned long data)
	struct sde_encoder_virt *sde_enc;
	struct msm_drm_private *priv;
	struct msm_drm_thread *event_thread;
	bool autorefresh_enabled = false;

	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
			!drm_enc->crtc) {
@@ -2970,28 +2971,16 @@ static void sde_encoder_vsync_event_handler(unsigned long data)
		return;
	}

	if (sde_enc->cur_master &&
		sde_enc->cur_master->ops.is_autorefresh_enabled)
		autorefresh_enabled =
			sde_enc->cur_master->ops.is_autorefresh_enabled(
						sde_enc->cur_master);

	/*
	 * Queue work to update the vsync event timer
	 * if autorefresh is enabled.
	 */
	SDE_EVT32_VERBOSE(autorefresh_enabled);
	if (autorefresh_enabled)
	kthread_queue_work(&event_thread->worker,
				&sde_enc->vsync_event_work);
	else
		del_timer(&sde_enc->vsync_event_timer);
}

static void sde_encoder_vsync_event_work_handler(struct kthread_work *work)
{
	struct sde_encoder_virt *sde_enc = container_of(work,
			struct sde_encoder_virt, vsync_event_work);
	bool autorefresh_enabled = false;
	int rc = 0;
	ktime_t wakeup_time;

	if (!sde_enc) {
@@ -2999,6 +2988,24 @@ static void sde_encoder_vsync_event_work_handler(struct kthread_work *work)
		return;
	}

	rc = _sde_encoder_power_enable(sde_enc, true);
	if (rc) {
		SDE_ERROR_ENC(sde_enc, "sde enc power enabled failed:%d\n", rc);
		return;
	}

	if (sde_enc->cur_master &&
		sde_enc->cur_master->ops.is_autorefresh_enabled)
		autorefresh_enabled =
			sde_enc->cur_master->ops.is_autorefresh_enabled(
						sde_enc->cur_master);

	_sde_encoder_power_enable(sde_enc, false);

	/* Update timer if autorefresh is enabled else return */
	if (!autorefresh_enabled)
		return;

	if (_sde_encoder_wakeup_time(&sde_enc->base, &wakeup_time))
		return;