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

Commit 9a5ee1cc authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: cleanup core perf implementation" into msm-4.9

parents 72eb2f85 4d424605
Loading
Loading
Loading
Loading
+62 −102
Original line number Diff line number Diff line
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -22,16 +22,10 @@
#include "msm_prop.h"

#include "sde_kms.h"
#include "sde_fence.h"
#include "sde_formats.h"
#include "sde_hw_sspp.h"
#include "sde_trace.h"
#include "sde_crtc.h"
#include "sde_plane.h"
#include "sde_encoder.h"
#include "sde_wb.h"
#include "sde_rsc.h"
#include "sde_core_perf.h"
#include "sde_trace.h"

static struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
{
@@ -59,20 +53,23 @@ static bool _sde_core_perf_crtc_is_power_on(struct drm_crtc *crtc)
static bool _sde_core_video_mode_intf_connected(struct drm_crtc *crtc)
{
	struct drm_crtc *tmp_crtc;
	bool intf_connected = false;

	if (!crtc)
		return 0;
		goto end;

	drm_for_each_crtc(tmp_crtc, crtc->dev) {
		if ((sde_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) &&
				_sde_core_perf_crtc_is_power_on(tmp_crtc)) {
			SDE_DEBUG("video interface connected crtc:%d\n",
				tmp_crtc->base.id);
			return true;
			intf_connected = true;
			goto end;
		}
	}

	return false;
end:
	return intf_connected;
}

int sde_core_perf_crtc_check(struct drm_crtc *crtc,
@@ -80,6 +77,7 @@ int sde_core_perf_crtc_check(struct drm_crtc *crtc,
{
	u32 bw, threshold;
	u64 bw_sum_of_intfs = 0;
	enum sde_crtc_client_type curr_client_type;
	bool is_video_mode;
	struct sde_crtc_state *sde_cstate;
	struct drm_crtc *tmp_crtc;
@@ -97,16 +95,18 @@ int sde_core_perf_crtc_check(struct drm_crtc *crtc,
	}

	/* we only need bandwidth check on real-time clients (interfaces) */
	if (sde_crtc_is_wb(crtc))
	if (sde_crtc_get_client_type(crtc) == NRT_CLIENT)
		return 0;

	sde_cstate = to_sde_crtc_state(state);

	bw_sum_of_intfs = sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
	curr_client_type = sde_crtc_get_client_type(crtc);

	drm_for_each_crtc(tmp_crtc, crtc->dev) {
		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
				sde_crtc_is_rt(tmp_crtc) && tmp_crtc != crtc) {
		    (sde_crtc_get_client_type(tmp_crtc) == curr_client_type) &&
		    (tmp_crtc != crtc)) {
			struct sde_crtc_state *tmp_cstate =
					to_sde_crtc_state(tmp_crtc->state);

@@ -131,7 +131,7 @@ int sde_core_perf_crtc_check(struct drm_crtc *crtc,
		return -E2BIG;
	} else if (bw > threshold) {
		sde_cstate->cur_perf.bw_ctl = 0;
		SDE_DEBUG("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
		SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
		return -E2BIG;
	}

@@ -158,23 +158,23 @@ static void _sde_core_perf_calc_crtc(struct sde_kms *kms,
			perf->max_per_pipe_ib, perf->bw_ctl);
}

static u64 _sde_core_perf_crtc_calc_client_vote(struct sde_kms *kms,
		struct drm_crtc *crtc, struct sde_core_perf_params *perf,
		bool nrt_client, u32 core_clk)
static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
		struct drm_crtc *crtc)
{
	u64 bw_sum_of_intfs = 0;
	u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota;
	struct sde_core_perf_params perf = {0};
	enum sde_crtc_client_type curr_client_type
					= sde_crtc_get_client_type(crtc);
	struct drm_crtc *tmp_crtc;
	struct sde_crtc_state *sde_cstate;
	struct msm_drm_private *priv = kms->dev->dev_private;

	drm_for_each_crtc(tmp_crtc, crtc->dev) {
		if (_sde_core_perf_crtc_is_power_on(crtc) &&
		    /* RealTime clients */
		    ((!nrt_client) ||
		    /* Non-RealTime clients */
		    (nrt_client && sde_crtc_is_nrt(tmp_crtc)))) {
			struct sde_crtc_state *sde_cstate =
					to_sde_crtc_state(tmp_crtc->state);
		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
		    (curr_client_type == sde_crtc_get_client_type(tmp_crtc))) {
			sde_cstate = to_sde_crtc_state(tmp_crtc->state);

			perf->max_per_pipe_ib = max(perf->max_per_pipe_ib,
			perf.max_per_pipe_ib = max(perf.max_per_pipe_ib,
				sde_cstate->cur_perf.max_per_pipe_ib);

			bw_sum_of_intfs += sde_cstate->cur_perf.bw_ctl;
@@ -185,57 +185,38 @@ static u64 _sde_core_perf_crtc_calc_client_vote(struct sde_kms *kms,
		}
	}

	return bw_sum_of_intfs;
}
	bus_ab_quota = max(bw_sum_of_intfs, kms->perf.perf_tune.min_bus_vote);
	bus_ib_quota = perf.max_per_pipe_ib;

static void _sde_core_perf_crtc_update_client_vote(struct sde_kms *kms,
	struct sde_core_perf_params *params, bool nrt_client, u64 bw_vote)
{
	struct msm_drm_private *priv = kms->dev->dev_private;
	u64 bus_ab_quota, bus_ib_quota;

	bus_ab_quota = max(bw_vote, kms->perf.perf_tune.min_bus_vote);
	bus_ib_quota = params->max_per_pipe_ib;
	switch (curr_client_type) {
	case NRT_CLIENT:
		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
				SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT,
				bus_ab_quota, bus_ib_quota);
		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "nrt",
				bus_ab_quota, bus_ib_quota);
		break;

	SDE_ATRACE_INT("bus_quota", bus_ib_quota);
	case RT_CLIENT:
		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
		nrt_client ? SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT :
				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
				bus_ab_quota, bus_ib_quota);
	SDE_DEBUG("client:%s ab=%llu ib=%llu\n", nrt_client ? "nrt" : "rt",
		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt",
				bus_ab_quota, bus_ib_quota);
}

static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
		struct drm_crtc *crtc, u32 core_clk)
{
	u64 bw_sum_of_rt_intfs = 0, bw_sum_of_nrt_intfs = 0;
	struct sde_core_perf_params params = {0};

	SDE_ATRACE_BEGIN(__func__);
		break;

	/*
	 * non-real time client
	 */
	if (sde_crtc_is_nrt(crtc)) {
		bw_sum_of_nrt_intfs = _sde_core_perf_crtc_calc_client_vote(
				kms, crtc, &params, true, core_clk);
		_sde_core_perf_crtc_update_client_vote(kms, &params, true,
			bw_sum_of_nrt_intfs);
	}
	case RT_RSC_CLIENT:
		sde_cstate = to_sde_crtc_state(crtc->state);
		sde_rsc_client_vote(sde_cstate->rsc_client, bus_ab_quota,
					bus_ib_quota);
		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt_rsc",
				bus_ab_quota, bus_ib_quota);
		break;

	/*
	 * real time client
	 */
	if (!sde_crtc_is_nrt(crtc) ||
		sde_crtc_is_wb(crtc)) {
		bw_sum_of_rt_intfs = _sde_core_perf_crtc_calc_client_vote(kms,
				crtc, &params, false, core_clk);
		_sde_core_perf_crtc_update_client_vote(kms, &params, false,
			bw_sum_of_rt_intfs);
	default:
		SDE_ERROR("invalid client type:%d\n", curr_client_type);
		break;
	}

	SDE_ATRACE_END(__func__);
}

/**
@@ -265,9 +246,9 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)

	sde_cstate = to_sde_crtc_state(crtc->state);

	/* only do this for command panel or writeback */
	/* only do this for command mode rt client (non-rsc client) */
	if ((sde_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) &&
			(sde_crtc_get_intf_mode(crtc) != INTF_MODE_WB_LINE))
		(sde_crtc_get_client_type(crtc) != RT_RSC_CLIENT))
		return;

	/*
@@ -288,14 +269,8 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
		sde_cstate->cur_perf.bw_ctl = 0;
		sde_cstate->new_perf.bw_ctl = 0;
		SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
		_sde_core_perf_crtc_update_bus(kms, crtc, 0);
	}
		_sde_core_perf_crtc_update_bus(kms, crtc);
	}

static int _sde_core_select_clk_lvl(struct sde_kms *kms,
			u32 clk_rate)
{
	return clk_round_rate(kms->perf.core_clk, clk_rate);
}

static u32 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
@@ -303,7 +278,6 @@ static u32 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
	u32 clk_rate = 0;
	struct drm_crtc *crtc;
	struct sde_crtc_state *sde_cstate;
	int ncrtc = 0;

	drm_for_each_crtc(crtc, kms->dev) {
		if (_sde_core_perf_crtc_is_power_on(crtc)) {
@@ -312,11 +286,9 @@ static u32 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
							clk_rate);
			clk_rate = clk_round_rate(kms->perf.core_clk, clk_rate);
		}
		ncrtc++;
	}
	clk_rate = _sde_core_select_clk_lvl(kms, clk_rate);

	SDE_DEBUG("clk:%u ncrtc:%d\n", clk_rate, ncrtc);
	SDE_DEBUG("clk:%u\n", clk_rate);

	return clk_rate;
}
@@ -351,8 +323,6 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc,
	SDE_DEBUG("crtc:%d stop_req:%d core_clk:%u\n",
			crtc->base.id, stop_req, kms->perf.core_clk_rate);

	SDE_ATRACE_BEGIN(__func__);

	old = &sde_cstate->cur_perf;
	new = &sde_cstate->new_perf;

@@ -392,38 +362,28 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc,
		update_clk = 1;
	}

	/*
	 * Calculate mdp clock before bandwidth calculation. If traffic shaper
	 * is enabled and clock increased, the bandwidth calculation can
	 * use the new clock for the rotator bw calculation.
	 */
	if (update_clk)
		clk_rate = _sde_core_perf_get_core_clk_rate(kms);

	if (update_bus)
		_sde_core_perf_crtc_update_bus(kms, crtc, clk_rate);
		_sde_core_perf_crtc_update_bus(kms, crtc);

	/*
	 * Update the clock after bandwidth vote to ensure
	 * bandwidth is available before clock rate is increased.
	 */
	if (update_clk) {
		SDE_ATRACE_INT(kms->perf.clk_name, clk_rate);
		clk_rate = _sde_core_perf_get_core_clk_rate(kms);

		SDE_EVT32(kms->dev, stop_req, clk_rate);
		ret = sde_power_clk_set_rate(&priv->phandle,
				kms->perf.clk_name, clk_rate);
		if (ret) {
			SDE_ERROR("failed to set %s clock rate %u\n",
					kms->perf.clk_name, clk_rate);
			goto end;
			return;
		}

		kms->perf.core_clk_rate = clk_rate;
		SDE_DEBUG("update clk rate = %d HZ\n", clk_rate);
	}

end:
	SDE_ATRACE_END(__func__);
}

#ifdef CONFIG_DEBUG_FS
+1 −14
Original line number Diff line number Diff line
@@ -417,7 +417,6 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc,
	SDE_EVT32(DRMID(crtc));

	/* identify connectors attached to this crtc */
	cstate->is_rt = false;
	cstate->num_connectors = 0;

	drm_for_each_connector(conn, crtc->dev)
@@ -425,9 +424,6 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc,
				cstate->num_connectors < MAX_CONNECTORS) {
			cstate->connectors[cstate->num_connectors++] = conn;
			sde_connector_prepare_fence(conn);

			if (conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
				cstate->is_rt = true;
		}

	if (cstate->num_connectors > 0 && cstate->connectors[0]->encoder)
@@ -440,15 +436,6 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc,
	sde_fence_prepare(&sde_crtc->output_fence);
}

bool sde_crtc_is_rt(struct drm_crtc *crtc)
{
	if (!crtc || !crtc->state) {
		SDE_ERROR("invalid crtc or state\n");
		return true;
	}
	return to_sde_crtc_state(crtc->state)->is_rt;
}

/* if file!=NULL, this is preclose potential cancel-flip path */
static void _sde_crtc_complete_flip(struct drm_crtc *crtc,
		struct drm_file *file)
@@ -1869,7 +1856,7 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v)
	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);

	seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
	seq_printf(s, "is_rt: %d\n", cstate->is_rt);
	seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
	seq_printf(s, "intf_mode: %d\n", cstate->intf_mode);
	seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
	seq_printf(s, "core_clk_rate: %u\n", cstate->cur_perf.core_clk_rate);
+22 −21
Original line number Diff line number Diff line
@@ -30,6 +30,20 @@
/* define the maximum number of in-flight frame events */
#define SDE_CRTC_FRAME_EVENT_SIZE	2

/**
 * enum sde_crtc_client_type: crtc client type
 * @RT_CLIENT:	RealTime client like video/cmd mode display
 *              voting through apps rsc
 * @NRT_CLIENT:	Non-RealTime client like WB display
 *              voting through apps rsc
 * @RT_RSC_CLIENT:	Realtime display RSC voting client
 */
enum sde_crtc_client_type {
	RT_CLIENT,
	NRT_CLIENT,
	RT_RSC_CLIENT,
};

/**
 * struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC
 * @hw_lm:	LM HW Driver context
@@ -136,8 +150,9 @@ struct sde_crtc {
 * @base: Base drm crtc state structure
 * @connectors    : Currently associated drm connectors
 * @num_connectors: Number of associated drm connectors
 * @is_rt         : Whether or not the current commit contains RT connectors
 * @intf_mode     : Interface mode of the primary connector
 * @rsc_mode      : Client vote through sde rsc
 * @rsc_client    : sde rsc client when mode is valid
 * @property_values: Current crtc property values
 * @input_fence_timeout_ns : Cached input fence timeout, in ns
 * @property_blobs: Reference pointers for blob properties
@@ -151,8 +166,9 @@ struct sde_crtc_state {

	struct drm_connector *connectors[MAX_CONNECTORS];
	int num_connectors;
	bool is_rt;
	enum sde_intf_mode intf_mode;
	bool rsc_mode;
	struct sde_rsc_client *rsc_client;

	uint64_t property_values[CRTC_PROP_COUNT];
	uint64_t input_fence_timeout_ns;
@@ -254,13 +270,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane);
 */
void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);

/**
 * sde_crtc_is_rt - query whether real time connectors are present on the crtc
 * @crtc: Pointer to drm crtc structure
 * Returns: True if a connector is present with real time constraints
 */
bool sde_crtc_is_rt(struct drm_crtc *crtc);

/**
 * sde_crtc_get_intf_mode - get interface mode of the given crtc
 * @crtc: Pointert to crtc
@@ -274,24 +283,16 @@ static inline enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
}

/**
 * sde_core_perf_crtc_is_wb - check if writeback is primary output of this crtc
 * sde_crtc_get_client_type - check the crtc type- rt, nrt, rsc, etc.
 * @crtc: Pointer to crtc
 */
static inline bool sde_crtc_is_wb(struct drm_crtc *crtc)
static inline bool sde_crtc_get_client_type(struct drm_crtc *crtc)
{
	struct sde_crtc_state *cstate =
			crtc ? to_sde_crtc_state(crtc->state) : NULL;

	return cstate ? (cstate->intf_mode == INTF_MODE_WB_LINE) : false;
}

/**
 * sde_crtc_is_nrt - check if primary output of this crtc is non-realtime client
 * @crtc: Pointer to crtc
 */
static inline bool sde_crtc_is_nrt(struct drm_crtc *crtc)
{
	return sde_crtc_is_wb(crtc);
	return cstate && (cstate->intf_mode == INTF_MODE_WB_LINE) ? NRT_CLIENT
		: cstate && cstate->rsc_mode ? RT_RSC_CLIENT : RT_CLIENT;
}

/**
+1 −3
Original line number Diff line number Diff line
@@ -862,8 +862,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
	if (sde_enc->disp_info.is_primary) {
		ret = sde_rsc_client_vote(sde_enc->rsc_client,
			SDE_POWER_HANDLE_DATA_BUS_IB_QUOTA,
			SDE_POWER_HANDLE_DATA_BUS_AB_QUOTA,
			true);
			SDE_POWER_HANDLE_DATA_BUS_AB_QUOTA);
		if (ret)
			SDE_ERROR("sde rsc client vote failed ret:%d\n", ret);
	}
@@ -1303,7 +1302,6 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc,
	}
	mutex_unlock(&sde_enc->enc_lock);


	return ret;
}

+1 −1
Original line number Diff line number Diff line
@@ -1203,7 +1203,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
		return 0;
	pstate->pending = true;

	psde->is_rt_pipe = sde_crtc_is_rt(crtc);
	psde->is_rt_pipe = (sde_crtc_get_client_type(crtc) != NRT_CLIENT);
	_sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);

	/* update roi config */
Loading