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

Commit f9fca5f3 authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran
Browse files

drm/msm/sde: avoid multi-display update during secure-session



Add extra validations during atomic check to avoid concurrent
display updates during secure-ui session.
- Fail crtc atomic_check for all other display(s),
  when secure crtc session is in progress.
- Fail secure crtc atomic_check, when any other crtc session
  for other display(s) are in progress.
As part of the change add checks in crtc to allow only
one blending stage configuration during secure-session.

Change-Id: I8aac488eae461db71b3bbd3bb1f0e91f6bb399eb
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent 06e4dc68
Loading
Loading
Loading
Loading
+38 −30
Original line number Diff line number Diff line
@@ -4312,13 +4312,14 @@ static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state,
}

static int _sde_crtc_check_secure_state(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
		struct drm_crtc_state *state, struct plane_state pstates[],
		int cnt)
{
	struct drm_encoder *encoder;
	struct sde_crtc_state *cstate;
	uint32_t secure;
	uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
	int encoder_cnt = 0;
	int encoder_cnt = 0, i;
	int rc;

	if (!crtc || !state) {
@@ -4328,31 +4329,40 @@ static int _sde_crtc_check_secure_state(struct drm_crtc *crtc,

	cstate = to_sde_crtc_state(state);

	secure = sde_crtc_get_property(cstate,
			CRTC_PROP_SECURITY_LEVEL);
	secure = sde_crtc_get_property(cstate, CRTC_PROP_SECURITY_LEVEL);

	rc = _sde_crtc_find_plane_fb_modes(state,
			&fb_ns,
			&fb_sec,
			&fb_sec_dir);
	rc = _sde_crtc_find_plane_fb_modes(state, &fb_ns, &fb_sec, &fb_sec_dir);
	if (rc)
		return rc;

	/**
	 * validate planes
	 * fb_sec_dir is for secure camera preview and secure display  use case,
	 * fb_sec is for secure video playback,
	 * fb_ns is for normal non secure use cases.
	if (secure == SDE_DRM_SEC_ONLY) {
		/*
		 * validate planes - only fb_sec_dir is allowed during sec_crtc
		 * - fb_sec_dir is for secure camera preview and
		 * secure display use case
		 * - fb_sec is for secure video playback
		 * - fb_ns is for normal non secure use cases
		 */
	if ((secure == SDE_DRM_SEC_ONLY) &&
			(fb_ns || fb_sec || (fb_sec && fb_sec_dir))) {
		if (fb_ns || fb_sec) {
			SDE_ERROR(
		"crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d\n",
			 "crtc%d: invalid fb_modes Sec:%d, NS:%d, Sec_Dir:%d\n",
				crtc->base.id, fb_sec, fb_ns, fb_sec_dir);
			return -EINVAL;
		}

	/**
		/* only one blending stage is allowed in sec_crtc */
		for (i = 1; i < cnt; i++) {
			if (pstates[i].stage != pstates[i-1].stage) {
				SDE_ERROR(
				  "crtc%d: invalid blend stages %d:%d, %d:%d\n",
				  crtc->base.id, i, pstates[i].stage,
				  i-1, pstates[i-1].stage);
				return -EINVAL;
			}
		}
	}

	/*
	 * secure_crtc is not allowed in a shared toppolgy
	 * across different encoders.
	 */
@@ -4361,17 +4371,15 @@ static int _sde_crtc_check_secure_state(struct drm_crtc *crtc,
			if (encoder->crtc ==  crtc)
				encoder_cnt++;

		if (encoder_cnt >
			MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) {
			SDE_ERROR(
				"crtc%d, invalid virtual encoder crtc%d\n",
				crtc->base.id,
				encoder_cnt);
		if (encoder_cnt > MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) {
			SDE_ERROR("crtc%d, invalid virtual encoder crtc%d\n",
				crtc->base.id, encoder_cnt);
			return -EINVAL;

		}
	}
	SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);

	return 0;
}

@@ -4428,10 +4436,6 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
	_sde_crtc_setup_is_ppsplit(state);
	_sde_crtc_setup_lm_bounds(crtc, state);

	rc = _sde_crtc_check_secure_state(crtc, state);
	if (rc)
		return rc;

	 /* get plane state for all drm planes associated with crtc state */
	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
		if (IS_ERR_OR_NULL(pstate)) {
@@ -4505,6 +4509,10 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
	/* assign mixer stages based on sorted zpos property */
	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);

	rc = _sde_crtc_check_secure_state(crtc, state, pstates, cnt);
	if (rc)
		goto end;

	rc = _sde_crtc_excl_dim_layer_check(state, pstates, cnt);
	if (rc)
		goto end;
+44 −36
Original line number Diff line number Diff line
@@ -1824,10 +1824,10 @@ static int sde_kms_check_secure_transition(struct msm_kms *kms,
	struct sde_kms *sde_kms;
	struct drm_device *dev;
	struct drm_crtc *crtc;
	struct drm_crtc *sec_crtc = NULL, *temp_crtc = NULL;
	struct drm_crtc *cur_crtc = NULL, *global_crtc = NULL;
	struct drm_crtc_state *crtc_state;
	int secure_crtc_cnt = 0, active_crtc_cnt = 0;
	int secure_global_crtc_cnt = 0, active_mode_crtc_cnt = 0;
	int active_crtc_cnt = 0, global_active_crtc_cnt = 0;
	bool sec_session = false, global_sec_session = false;
	int i;

	if (!kms || !state) {
@@ -1835,56 +1835,64 @@ static int sde_kms_check_secure_transition(struct msm_kms *kms,
		SDE_ERROR("invalid arguments\n");
	}

	/* iterate state object for active and secure crtc */
	sde_kms = to_sde_kms(kms);
	dev = sde_kms->dev;

	/* iterate state object for active secure/non-secure crtc */
	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		if (!crtc_state->active)
			continue;

		active_crtc_cnt++;
		if (sde_crtc_get_secure_level(crtc, crtc_state) ==
				SDE_DRM_SEC_ONLY) {
			sec_crtc = crtc;
			secure_crtc_cnt++;
		}
	}

	/* bail out from further validation if no secure ctrc */
	if (!secure_crtc_cnt)
		return 0;
				SDE_DRM_SEC_ONLY)
			sec_session = true;

	if ((secure_crtc_cnt > MAX_ALLOWED_SECURE_CLIENT_CNT) ||
		(secure_crtc_cnt &&
		 (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE))) {
		SDE_ERROR("Secure check failed active:%d, secure:%d\n",
				active_crtc_cnt, secure_crtc_cnt);
		return -EPERM;
		cur_crtc = crtc;
	}

	sde_kms = to_sde_kms(kms);
	dev = sde_kms->dev;
	/* iterate global list for active and secure crtc */
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {

		if (!crtc->state->active)
			continue;

		active_mode_crtc_cnt++;

		global_active_crtc_cnt++;
		if (sde_crtc_get_secure_level(crtc, crtc->state) ==
				SDE_DRM_SEC_ONLY) {
			secure_global_crtc_cnt++;
			temp_crtc = crtc;
		}
				SDE_DRM_SEC_ONLY)
			global_sec_session = true;

		global_crtc = crtc;
	}

	/**
	 * if more than one crtc is active fail
	 * check if the previous and current commit secure
	 * are same
	/*
	 * - fail secure crtc commit, if any other crtc session is already
	 *   in progress
	 * - fail non-secure crtc commit, if any secure crtc session is already
	 *   in progress
	 */
	if (secure_crtc_cnt && ((active_mode_crtc_cnt > 1) ||
			(secure_global_crtc_cnt && (temp_crtc != sec_crtc))))
		SDE_ERROR("Secure check failed active:%d crtc_id:%d\n",
				active_mode_crtc_cnt, temp_crtc->base.id);
	if (global_sec_session || sec_session) {
		if ((global_active_crtc_cnt >
					MAX_ALLOWED_CRTC_CNT_DURING_SECURE) ||
		    (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE)) {
			SDE_ERROR(
			"Secure check failed global_active:%d active:%d\n",
				global_active_crtc_cnt, active_crtc_cnt);
			return -EPERM;

		/*
		 * As only one crtc is allowed during secure session, the crtc
		 * in this commit should match with the global crtc, if it
		 * exists
		 */
		} else if (global_crtc && (global_crtc != cur_crtc)) {
			SDE_ERROR(
			    "crtc%d-sec%d not allowed during crtc%d-sec%d\n",
				cur_crtc->base.id, sec_session,
				global_crtc->base.id, global_sec_session);
			return -EPERM;
		}

	}

	return 0;
}