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

Commit b8e0c667 authored by Guchun Chen's avatar Guchun Chen
Browse files

drm: sde: Check commit's validity when starting splash handoff



User maybe send null commit with invalid frame buffer
to kernel, so early splash's handoff should wait for
one valid commit coming with active fb.

CRs-Fixed: 2225630
Change-Id: I5ef0809791d697be264787ebe7a6ec58704cb310
Signed-off-by: default avatarGuchun Chen <guchunc@codeaurora.org>
parent 845a8313
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -572,6 +572,7 @@ void sde_connector_complete_commit(struct drm_connector *connector)
{
	struct drm_device *dev;
	struct msm_drm_private *priv;
	struct sde_connector *c_conn;

	if (!connector) {
		SDE_ERROR("invalid connector\n");
@@ -584,11 +585,17 @@ void sde_connector_complete_commit(struct drm_connector *connector)
	/* signal connector's retire fence */
	sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);

	/* after first vsync comes,
	 * early splash resource should start to be released.
	/*
	 * After LK totally exits, LK's early splash resource
	 * should be released.
	 */
	if (sde_splash_get_lk_complete_status(priv->kms))
		sde_splash_free_resource(priv->kms, &priv->phandle);
	if (sde_splash_get_lk_complete_status(priv->kms)) {
		c_conn = to_sde_connector(connector);

		sde_splash_free_resource(priv->kms, &priv->phandle,
					c_conn->connector_type,
					c_conn->display);
	}

}

+4 −4
Original line number Diff line number Diff line
@@ -345,8 +345,8 @@ static void sde_kms_prepare_commit(struct msm_kms *kms,

	if (sde_kms->splash_info.handoff &&
		sde_kms->splash_info.display_splash_enabled)
		sde_splash_lk_stop_splash(kms);
	else
		sde_splash_lk_stop_splash(kms, state);

	sde_power_resource_enable(&priv->phandle,
			sde_kms->core_client, true);
}
+110 −24
Original line number Diff line number Diff line
@@ -313,6 +313,15 @@ static void _sde_splash_sent_pipe_update_uevent(struct sde_kms *sde_kms)
	kfree(event_string);
}

static void _sde_splash_get_connector_ref_cnt(struct sde_splash_info *sinfo,
					u32 *hdmi_cnt, u32 *dsi_cnt)
{
	mutex_lock(&sde_splash_lock);
	*hdmi_cnt = sinfo->hdmi_connector_cnt;
	*dsi_cnt = sinfo->dsi_connector_cnt;
	mutex_unlock(&sde_splash_lock);
}

static int _sde_splash_free_module_resource(struct msm_mmu *mmu,
				struct sde_splash_info *sinfo)
{
@@ -339,6 +348,29 @@ static int _sde_splash_free_module_resource(struct msm_mmu *mmu,
	return 0;
}

static bool _sde_splash_validate_commit(struct sde_kms *sde_kms,
					struct drm_atomic_state *state)
{
	int i, nplanes;
	struct drm_plane *plane;
	struct drm_device *dev = sde_kms->dev;

	nplanes = dev->mode_config.num_total_plane;

	for (i = 0; i < nplanes; i++) {
		plane = state->planes[i];

		/*
		 * As plane state has been swapped, we need to check
		 * fb in state->planes, not fb in state->plane_state.
		 */
		if (plane && plane->fb)
			return true;
	}

	return false;
}

__ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms)
{
	struct sde_kms *sde_kms;
@@ -369,8 +401,7 @@ __ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms)
			sde_power_data_bus_bandwidth_ctrl(phandle,
					sde_kms->core_client, false);

			ret = -EINVAL;
			break;
			return -EINVAL;
		}
	}

@@ -716,11 +747,17 @@ bool sde_splash_get_lk_complete_status(struct msm_kms *kms)
}

int sde_splash_free_resource(struct msm_kms *kms,
			struct sde_power_handle *phandle)
			struct sde_power_handle *phandle,
			int connector_type, void *display)
{
	struct sde_kms *sde_kms;
	struct sde_splash_info *sinfo;
	struct msm_mmu *mmu;
	struct dsi_display *dsi_display = display;
	int ret = 0;
	int hdmi_conn_count = 0;
	int dsi_conn_count = 0;
	static const char *last_commit_display_type = "unknown";

	if (!phandle || !kms) {
		SDE_ERROR("invalid phandle/kms.\n");
@@ -734,12 +771,21 @@ int sde_splash_free_resource(struct msm_kms *kms,
		return -EINVAL;
	}

	/* Get connector number where the early splash in on. */
	_sde_splash_get_connector_ref_cnt(sinfo, &hdmi_conn_count,
						&dsi_conn_count);

	mutex_lock(&sde_splash_lock);
	if (!sinfo->handoff) {
		mutex_unlock(&sde_splash_lock);
		return 0;
	}

	/*
	 * Start to free all LK's resource till user commit happens
	 * on each display which early splash is enabled on.
	 */
	if (hdmi_conn_count == 0 && dsi_conn_count == 0) {
		mmu = sde_kms->aspace[0]->mmu;
		if (!mmu) {
			mutex_unlock(&sde_splash_lock);
@@ -759,24 +805,63 @@ int sde_splash_free_resource(struct msm_kms *kms,
		sde_power_data_bus_bandwidth_ctrl(phandle,
					sde_kms->core_client, false);

		/*
		 * Turn off MDP core power to keep power on/off operations
		 * be matched, as MDP core power is enabled already when
		 * early splash is enabled.
		 */
		sde_power_resource_enable(phandle,
					sde_kms->core_client, false);

		/* send uevent to notify user to recycle resource */
		_sde_splash_sent_pipe_update_uevent(sde_kms);

	/* Finally mark handoff flag to false to say handoff is complete */
		/* Finally mark handoff flag to false to say
		 * handoff is complete.
		 */
		sinfo->handoff = false;

		DRM_INFO("HDMI and DSI resource handoff is completed\n");

		mutex_unlock(&sde_splash_lock);
		return 0;
	}

	/*
	 * Ensure user commit happens on different connectors
	 * who has splash.
	 */
	switch (connector_type) {
	case DRM_MODE_CONNECTOR_HDMIA:
		if (sinfo->hdmi_connector_cnt == 1)
			sinfo->hdmi_connector_cnt--;
		break;
	case DRM_MODE_CONNECTOR_DSI:
		if (strcmp(dsi_display->display_type, "unknown") &&
			strcmp(last_commit_display_type,
				dsi_display->display_type)) {
			if (sinfo->dsi_connector_cnt >= 1)
				sinfo->dsi_connector_cnt--;

			last_commit_display_type = dsi_display->display_type;
		}
		break;
	default:
		ret = -EINVAL;
		SDE_ERROR("%s: invalid connector_type %d\n",
					__func__, connector_type);
	}

	mutex_unlock(&sde_splash_lock);
	return ret;
}

/*
 * In below function, it will
 * 1. Notify LK to stop display splash.
 * 2. Set DOMAIN_ATTR_EARLY_MAP to 1 to enable stage 1 translation in iommu.
 */
int sde_splash_lk_stop_splash(struct msm_kms *kms)
int sde_splash_lk_stop_splash(struct msm_kms *kms,
				struct drm_atomic_state *state)
{
	struct sde_splash_info *sinfo;
	struct msm_mmu *mmu;
@@ -792,7 +877,8 @@ int sde_splash_lk_stop_splash(struct msm_kms *kms)

	/* Monitor LK's status and tell it to exit. */
	mutex_lock(&sde_splash_lock);
	if (sinfo->display_splash_enabled) {
	if (_sde_splash_validate_commit(sde_kms, state) &&
			sinfo->display_splash_enabled) {
		if (_sde_splash_lk_check(sde_kms->hw_intr))
			_sde_splash_notify_lk_stop_splash(sde_kms->hw_intr);

+12 −12
Original line number Diff line number Diff line
@@ -17,9 +17,6 @@
#include "msm_mmu.h"
#include "sde_hw_mdss.h"

#define SPLASH_CTL_MAX 5
#define SPLASH_LM_MAX 7

enum splash_connector_type {
	SPLASH_DSI = 0,
	SPLASH_HDMI,
@@ -35,13 +32,13 @@ struct splash_ctl_top {
	u32 value;
	u8 intf_sel;
	u8 ctl_lm_cnt;
	struct splash_lm_hw lm[SPLASH_LM_MAX];
	struct splash_lm_hw lm[LM_MAX - LM_0];
};

struct sde_res_data {
	struct splash_ctl_top top[SPLASH_CTL_MAX];
	u8 ctl_ids[SPLASH_CTL_MAX];
	u8 lm_ids[SPLASH_LM_MAX];
	struct splash_ctl_top top[CTL_MAX - CTL_0];
	u8 ctl_ids[CTL_MAX - CTL_0];
	u8 lm_ids[LM_MAX - LM_0];
	u8 ctl_top_cnt;
	u8 lm_cnt;
};
@@ -121,18 +118,21 @@ void sde_splash_setup_connector_count(struct sde_splash_info *sinfo,
/**
 * sde_splash_lk_stop_splash.
 *
 * Tell LK to stop display splash.
 * Tell LK to stop display splash once one valid user commit arrives.
 */
int sde_splash_lk_stop_splash(struct msm_kms *kms);
int sde_splash_lk_stop_splash(struct msm_kms *kms,
				struct drm_atomic_state *state);

/**
 * sde_splash_free_resource.
 *
 * According to input connector_type, free
 * HDMI's and DSI's resource respectively.
 * To free all LK's resource, including free reserved memory to system,
 * withdraw data bus vote, disable MDP core power, send uevent to user
 * to recycle pipe etc.
 */
int sde_splash_free_resource(struct msm_kms *kms,
			struct sde_power_handle *phandle);
			struct sde_power_handle *phandle,
			int connector_type, void *display);

/**
 * sde_splash_parse_memory_dt.