Răsfoiți Sursa

Merge "disp: msm: sde: hold vmlock only during transition in check phase"

qctecmdr 3 ani în urmă
părinte
comite
a3fc520ea7
1 a modificat fișierele cu 106 adăugiri și 109 ștergeri
  1. 106 109
      msm/sde/sde_kms.c

+ 106 - 109
msm/sde/sde_kms.c

@@ -2754,94 +2754,37 @@ backoff:
 	goto retry;
 }
 
-static int sde_kms_check_vm_request(struct msm_kms *kms,
-				    struct drm_atomic_state *state)
+static int _sde_kms_validate_vm_request(struct drm_atomic_state *state, struct sde_kms *sde_kms,
+		enum sde_crtc_vm_req vm_req, bool vm_owns_hw)
 {
-	struct sde_kms *sde_kms;
-	struct drm_device *dev;
-	struct drm_crtc *crtc;
-	struct drm_encoder *encoder;
+	struct drm_crtc *crtc, *active_crtc = NULL, *global_active_crtc = NULL;
 	struct drm_crtc_state *new_cstate, *old_cstate, *active_cstate;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct drm_connector_state *new_connstate;
+	struct sde_vm_ops *vm_ops = sde_vm_get_ops(sde_kms);
+	struct sde_mdss_cfg *catalog = sde_kms->catalog;
+	struct sde_connector *sde_conn;
+	struct dsi_display *dsi_display;
 	uint32_t i, commit_crtc_cnt = 0, global_crtc_cnt = 0;
 	uint32_t crtc_encoder_cnt = 0;
-	struct drm_crtc *active_crtc = NULL, *global_active_crtc = NULL;
-	enum sde_crtc_vm_req old_vm_req = VM_REQ_NONE, new_vm_req = VM_REQ_NONE;
-	struct sde_vm_ops *vm_ops;
-	bool vm_req_active = false;
-	bool vm_owns_hw;
 	enum sde_crtc_idle_pc_state idle_pc_state;
-	struct sde_mdss_cfg *catalog;
 	int rc = 0;
-	struct sde_connector *sde_conn;
-	struct dsi_display *dsi_display;
-	struct drm_connector *connector;
-	struct drm_connector_state *new_connstate;
-
-	if (!kms || !state)
-		return -EINVAL;
 
-	sde_kms = to_sde_kms(kms);
-	dev = sde_kms->dev;
-	catalog = sde_kms->catalog;
-
-	vm_ops = sde_vm_get_ops(sde_kms);
-	if (!vm_ops)
-		return 0;
-
-	if (!vm_ops->vm_request_valid || !vm_ops->vm_owns_hw ||
-				!vm_ops->vm_acquire)
-		return -EINVAL;
-
-	sde_vm_lock(sde_kms);
-	vm_owns_hw = sde_vm_owns_hw(sde_kms);
 	for_each_oldnew_crtc_in_state(state, crtc, old_cstate, new_cstate, i) {
-		struct sde_crtc_state *old_state = NULL, *new_state = NULL;
+		struct sde_crtc_state *new_state = NULL;
 
 		if (!new_cstate->active && !old_cstate->active)
 			continue;
 
 		new_state = to_sde_crtc_state(new_cstate);
-		new_vm_req = sde_crtc_get_property(new_state,
-				CRTC_PROP_VM_REQ_STATE);
-
-		old_state = to_sde_crtc_state(old_cstate);
-		old_vm_req = sde_crtc_get_property(old_state,
-				CRTC_PROP_VM_REQ_STATE);
-
-		/*
-		 * No active request if the transition is from
-		 * VM_REQ_NONE to VM_REQ_NONE
-		 */
-		if (old_vm_req || new_vm_req) {
-			rc = vm_ops->vm_request_valid(sde_kms,
-					old_vm_req, new_vm_req);
-			if (rc) {
-				SDE_ERROR(
-				"VM transition check failed; o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n",
-					old_vm_req, new_vm_req, vm_owns_hw, rc);
-				goto end;
-			} else if (old_vm_req == VM_REQ_ACQUIRE &&
-					new_vm_req == VM_REQ_NONE) {
-				SDE_DEBUG(
-				"VM transition valid; ignore further checks\n");
-			} else {
-				vm_req_active = true;
-			}
-		}
-
-		idle_pc_state = sde_crtc_get_property(new_state,
-						CRTC_PROP_IDLE_PC_STATE);
-
+		idle_pc_state = sde_crtc_get_property(new_state, CRTC_PROP_IDLE_PC_STATE);
 		active_crtc = crtc;
 		active_cstate = new_cstate;
 		commit_crtc_cnt++;
 	}
 
-	/* return early if no active vm request */
-	if (!vm_req_active)
-		goto end;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+	list_for_each_entry(crtc, &sde_kms->dev->mode_config.crtc_list, head) {
 		if (!crtc->state->active)
 			continue;
 
@@ -2850,14 +2793,10 @@ static int sde_kms_check_vm_request(struct msm_kms *kms,
 	}
 
 	if (active_crtc) {
-		drm_for_each_encoder_mask(encoder, active_crtc->dev,
-				active_cstate->encoder_mask)
+		drm_for_each_encoder_mask(encoder, active_crtc->dev, active_cstate->encoder_mask)
 			crtc_encoder_cnt++;
 	}
 
-	SDE_EVT32(old_vm_req, new_vm_req, vm_owns_hw);
-	SDE_DEBUG("VM  o_state:%d, n_state:%d, hw_owner:%d\n", old_vm_req, new_vm_req, vm_owns_hw);
-
 	for_each_new_connector_in_state(state, connector, new_connstate, i) {
 		int conn_mask = active_cstate->connector_mask;
 
@@ -2865,61 +2804,119 @@ static int sde_kms_check_vm_request(struct msm_kms *kms,
 			sde_conn = to_sde_connector(connector);
 			dsi_display = (struct dsi_display *) sde_conn->display;
 
-			SDE_EVT32(DRMID(connector), DRMID(active_crtc), i,
-					dsi_display->type,
-					dsi_display->trusted_vm_env);
-			SDE_DEBUG(
-			"VM display:%s, conn:%d, crtc:%d, type:%d, tvm:%d,",
-					dsi_display->name, DRMID(connector),
-					DRMID(active_crtc), dsi_display->type,
+			SDE_EVT32(DRMID(connector), DRMID(active_crtc), i, dsi_display->type,
 					dsi_display->trusted_vm_env);
+			SDE_DEBUG("VM display:%s, conn:%d, crtc:%d, type:%d, tvm:%d\n",
+					dsi_display->name, DRMID(connector), DRMID(active_crtc),
+					dsi_display->type, dsi_display->trusted_vm_env);
 			break;
 		}
 	}
 
 	/* Check for single crtc commits only on valid VM requests */
 	if (active_crtc && global_active_crtc &&
-		(commit_crtc_cnt > catalog->max_trusted_vm_displays ||
-			global_crtc_cnt > catalog->max_trusted_vm_displays ||
-			active_crtc != global_active_crtc)) {
-		SDE_ERROR(
-		"VM switch failed; MAX:%d a_cnt:%d g_cnt:%d a_crtc:%d g_crtc:%d\n",
-			   catalog->max_trusted_vm_displays,
-			   commit_crtc_cnt, global_crtc_cnt, DRMID(active_crtc),
-			   DRMID(global_active_crtc));
-		rc =  -E2BIG;
-		goto end;
-
-	} else if ((new_vm_req == VM_REQ_RELEASE) &&
-	    ((idle_pc_state == IDLE_PC_ENABLE) ||
-		(crtc_encoder_cnt > TRUSTED_VM_MAX_ENCODER_PER_CRTC))) {
+			(commit_crtc_cnt > catalog->max_trusted_vm_displays ||
+			 global_crtc_cnt > catalog->max_trusted_vm_displays ||
+			 active_crtc != global_active_crtc)) {
+		SDE_ERROR("VM switch failed; MAX:%d a_cnt:%d g_cnt:%d a_crtc:%d g_crtc:%d\n",
+			  catalog->max_trusted_vm_displays, commit_crtc_cnt, global_crtc_cnt,
+			  DRMID(active_crtc), DRMID(global_active_crtc));
+		return  -E2BIG;
+	} else if ((vm_req == VM_REQ_RELEASE) &&
+		   ((idle_pc_state == IDLE_PC_ENABLE) ||
+		    (crtc_encoder_cnt > TRUSTED_VM_MAX_ENCODER_PER_CRTC))) {
 		/*
 		 * disable idle-pc before releasing the HW
 		 * allow only specified number of encoders on a given crtc
 		 */
-		SDE_ERROR(
-			"VM switch failed; idle-pc:%d max:%d encoder_cnt:%d\n",
-				idle_pc_state, TRUSTED_VM_MAX_ENCODER_PER_CRTC,
-				crtc_encoder_cnt);
-		rc = -EINVAL;
-		goto end;
+		SDE_ERROR("VM switch failed; idle-pc:%d max:%d encoder_cnt:%d\n",
+				idle_pc_state, TRUSTED_VM_MAX_ENCODER_PER_CRTC, crtc_encoder_cnt);
+		return -EINVAL;
 	}
 
-	if ((new_vm_req == VM_REQ_ACQUIRE) && !vm_owns_hw) {
+	if ((vm_req == VM_REQ_ACQUIRE) && !vm_owns_hw) {
 		rc = vm_ops->vm_acquire(sde_kms);
 		if (rc) {
-			SDE_ERROR(
-			"VM acquire failed; o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n",
-				old_vm_req, new_vm_req, vm_owns_hw, rc);
-			goto end;
+			SDE_ERROR("VM acquire failed; hw_owner:%d, rc:%d\n", vm_owns_hw, rc);
+			return rc;
 		}
 
 		if (vm_ops->vm_resource_init)
 			rc = vm_ops->vm_resource_init(sde_kms, state);
 	}
 
-end:
-	sde_vm_unlock(sde_kms);
+	return rc;
+}
+
+static int sde_kms_check_vm_request(struct msm_kms *kms,
+				    struct drm_atomic_state *state)
+{
+	struct sde_kms *sde_kms;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *new_cstate, *old_cstate;
+	struct sde_vm_ops *vm_ops;
+	enum sde_crtc_vm_req old_vm_req = VM_REQ_NONE, new_vm_req = VM_REQ_NONE;
+	int i, rc = 0;
+	bool vm_req_active = false;
+	bool vm_owns_hw;
+
+	if (!kms || !state)
+		return -EINVAL;
+
+	sde_kms = to_sde_kms(kms);
+	vm_ops = sde_vm_get_ops(sde_kms);
+	if (!vm_ops)
+		return 0;
+
+	if (!vm_ops->vm_request_valid || !vm_ops->vm_owns_hw || !vm_ops->vm_acquire)
+		return -EINVAL;
+
+	/* check for an active vm request */
+	for_each_oldnew_crtc_in_state(state, crtc, old_cstate, new_cstate, i) {
+		struct sde_crtc_state *old_state = NULL, *new_state = NULL;
+
+		if (!new_cstate->active && !old_cstate->active)
+			continue;
+
+		new_state = to_sde_crtc_state(new_cstate);
+		new_vm_req = sde_crtc_get_property(new_state, CRTC_PROP_VM_REQ_STATE);
+
+		old_state = to_sde_crtc_state(old_cstate);
+		old_vm_req = sde_crtc_get_property(old_state, CRTC_PROP_VM_REQ_STATE);
+
+		/* No active request if the transition is from VM_REQ_NONE to VM_REQ_NONE */
+		if (old_vm_req || new_vm_req) {
+			if (!vm_req_active) {
+				sde_vm_lock(sde_kms);
+				vm_owns_hw = sde_vm_owns_hw(sde_kms);
+			}
+
+			rc = vm_ops->vm_request_valid(sde_kms, old_vm_req, new_vm_req);
+			if (rc) {
+				SDE_ERROR(
+				"VM transition check failed; o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n",
+						old_vm_req, new_vm_req, vm_owns_hw, rc);
+				sde_vm_unlock(sde_kms);
+				vm_req_active = false;
+				break;
+			} else if (old_vm_req == VM_REQ_ACQUIRE && new_vm_req == VM_REQ_NONE) {
+				SDE_DEBUG("VM transition valid; ignore further checks\n");
+				if (!vm_req_active)
+					sde_vm_unlock(sde_kms);
+			} else {
+				vm_req_active = true;
+			}
+		}
+	}
+
+	/* validate active requests and perform acquire if necessary */
+	if (vm_req_active) {
+		rc = _sde_kms_validate_vm_request(state, sde_kms, new_vm_req, vm_owns_hw);
+		sde_vm_unlock(sde_kms);
+		SDE_EVT32(old_vm_req, new_vm_req, vm_req_active, vm_owns_hw, rc);
+		SDE_DEBUG("VM  o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n", old_vm_req, new_vm_req,
+				vm_req_active ? vm_owns_hw : -1, rc);
+	}
 
 	return rc;
 }