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

Commit c2262757 authored by Raviteja Tamatam's avatar Raviteja Tamatam Committed by Shubhashree Dhar
Browse files

drm/msm/sde: stage border fill after ctl start timeout



In some error cases ctl start irq is delayed more than ctl start
timeout period and it is received after programming the
next commit CTL registers but before next flush. Due to this
only new CTL register configuration takes effect but not the pipe
configuration. This is leading to smmu fault. Staging border-fill
in these cases after ctl start timeout will help prevent illegal
iova 0x0 (non-configured pipe) transactions onto the bus.

Change-Id: I85418df3a922a8468f31adc285fac217e8f2eee4
Signed-off-by: default avatarRaviteja Tamatam <travitej@codeaurora.org>
parent 5e276334
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -941,6 +941,26 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc,
	return true;
}

static int _sde_crtc_get_ctlstart_timeout(struct drm_crtc *crtc)
{
	struct drm_encoder *encoder;
	int rc = 0;

	if (!crtc || !crtc->dev)
		return 0;

	list_for_each_entry(encoder,
			&crtc->dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
			continue;

		if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_CMD)
			rc += sde_encoder_get_ctlstart_timeout_state(encoder);
	}

	return rc;
}

static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer,
	struct sde_plane_state *pstate, struct sde_format *format)
{
@@ -3709,7 +3729,13 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	if (unlikely(!sde_crtc->num_mixers))
		goto end;

	if (_sde_crtc_get_ctlstart_timeout(crtc)) {
		_sde_crtc_blend_setup(crtc, old_state, false);
		SDE_ERROR("border fill only commit after ctlstart timeout\n");
	} else {
		_sde_crtc_blend_setup(crtc, old_state, true);
	}

	_sde_crtc_dest_scaler_setup(crtc);

	/* cancel the idle notify delayed work */
+17 −0
Original line number Diff line number Diff line
@@ -3545,6 +3545,23 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc)
	return 0;
}

int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	int i, count = 0;

	if (!drm_enc)
		return 0;

	sde_enc = to_sde_encoder_virt(drm_enc);

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		count += atomic_read(&sde_enc->phys_encs[i]->ctlstart_timeout);
		atomic_set(&sde_enc->phys_encs[i]->ctlstart_timeout, 0);
	}

	return count;
}
/**
 * _sde_encoder_trigger_flush - trigger flush for a physical encoder
 * drm_enc: Pointer to drm encoder structure
+7 −0
Original line number Diff line number Diff line
@@ -331,4 +331,11 @@ void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable);
 */
int sde_encoder_in_cont_splash(struct drm_encoder *enc);

/**
 * sde_encoder_get_ctlstart_timeout_state - checks if ctl start timeout happened
 * @drm_enc:    Pointer to drm encoder structure
 * @Return:     non zero value if ctl start timeout occurred
 */
int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *enc);

#endif /* __SDE_ENCODER_H__ */
+2 −0
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ struct sde_encoder_irq {
 * @pending_retire_fence_cnt:   Atomic counter tracking the pending retire
 *                              fences that have to be signalled.
 * @pending_kickoff_wq:		Wait queue for blocking until kickoff completes
 * @ctlstart_timeout:		Indicates if ctl start timeout occurred
 * @irq:			IRQ tracking structures
 * @has_intf_te:		Interface TE configuration support
 * @cont_splash_single_flush	Variable to check if single flush is enabled.
@@ -328,6 +329,7 @@ struct sde_encoder_phys {
	atomic_t pending_ctlstart_cnt;
	atomic_t pending_kickoff_cnt;
	atomic_t pending_retire_fence_cnt;
	atomic_t ctlstart_timeout;
	wait_queue_head_t pending_kickoff_wq;
	struct sde_encoder_irq irq[INTR_IDX_MAX];
	bool has_intf_te;
+5 −0
Original line number Diff line number Diff line
@@ -214,6 +214,7 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
				phys_enc,
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
		atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
		atomic_set(&phys_enc->ctlstart_timeout, 0);
	}

	/* notify all synchronous clients first, then asynchronous clients */
@@ -317,6 +318,7 @@ static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)

	ctl = phys_enc->hw_ctl;
	atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
	atomic_set(&phys_enc->ctlstart_timeout, 0);

	time_diff_us = ktime_us_delta(ktime_get(), cmd_enc->rd_ptr_timestamp);

@@ -1302,6 +1304,7 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
		SDE_ERROR("invalid encoder\n");
		return;
	}
	atomic_set(&phys_enc->ctlstart_timeout, 0);
	SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n",
			phys_enc->hw_pp->idx - PINGPONG_0,
			phys_enc->hw_intf->idx - INTF_0,
@@ -1470,6 +1473,7 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start(
				 SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
			atomic_add_unless(
				&phys_enc->pending_ctlstart_cnt, -1, 0);
			atomic_inc_return(&phys_enc->ctlstart_timeout);
		}

	}
@@ -1799,6 +1803,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
	atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
	atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0);
	atomic_set(&cmd_enc->pending_vblank_cnt, 0);
	atomic_set(&phys_enc->ctlstart_timeout, 0);
	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
	init_waitqueue_head(&cmd_enc->pending_vblank_wq);
	atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);