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

Commit d7830d36 authored by Vikram Mulukutla's avatar Vikram Mulukutla
Browse files

clk: msm: clock-rpm: Don't send unnecessary RPM requests



Fix an ancient inefficiency where an active-set vote with
the same value may be sent twice. This also applies to the
sleep set, but sleep set requests are buffered and so are
not sent to the RPM until power collapse anyway. In any
case apply the same treatment to both contexts.

Consider an RPM clock A and its peer B. It is not possible
to simply look at the peer clock's request and determine if a
duplicate rate needs to be sent. B is also A's peer, therefore
it is not possible to know if the peer's last request was actually
sent or it was short circuited by the same logic that A is
working through. There needs to exist data storage common to
both clocks in order to ensure that requests are not dropped.

Therefore, implement this optimization by simply caching the
last request in a variable that is common to *both* clocks,
the active set clocks and the active+sleep clock. If the new
request is the same as the previous request, don't send it
to the RPM.

Change-Id: Id0e0a96fa5ea4f7422454e85001adca6071da6b6
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
parent 861a4ae9
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -31,14 +31,42 @@
static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
				uint32_t context)
{
	int ret;

	struct msm_rpm_kvp kvp = {
		.key = r->rpm_key,
		.data = (void *)&value,
		.length = sizeof(value),
	};

	return msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id,
	switch (context) {
	case MSM_RPM_CTX_ACTIVE_SET:
		if (*r->last_active_set_vote == value)
			return 0;
		break;
	case MSM_RPM_CTX_SLEEP_SET:
		 if (*r->last_sleep_set_vote == value)
			return 0;
		break;
	default:
		return -EINVAL;
	};

	ret = msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id,
			&kvp, 1);
	if (ret)
		return ret;

	switch (context) {
	case MSM_RPM_CTX_ACTIVE_SET:
		*r->last_active_set_vote = value;
		break;
	case MSM_RPM_CTX_SLEEP_SET:
		*r->last_sleep_set_vote = value;
		break;
	}

	return 0;
}

static int clk_rpmrs_handoff_smd(struct rpm_clk *r)
+27 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ struct rpm_clk {
	struct clk_rpmrs_data *rpmrs_data;
	struct rpm_clk *peer;
	struct clk c;
	uint32_t *last_active_set_vote;
	uint32_t *last_sleep_set_vote;
};

static inline struct rpm_clk *to_rpm_clk(struct clk *clk)
@@ -58,9 +60,24 @@ int vote_bimc(struct rpm_clk *r, uint32_t value);

extern struct clk_rpmrs_data clk_rpmrs_data_smd;

/*
 * A note on name##last_{active,sleep}_set_vote below:
 * We track the last active and sleep set votes across both
 * active-only and active+sleep set clocks. We use the same
 * tracking variables for both clocks in order to keep both
 * updated about the last vote irrespective of which clock
 * actually made the request. This is the only way to allow
 * optimizations that prevent duplicate requests from being sent
 * to the RPM. Separate tracking does not work since it is not
 * possible to know if the peer's last request was actually sent
 * to the RPM.
 */

#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, key, \
				rpmrsdata) \
	static struct rpm_clk active; \
	static uint32_t name##last_active_set_vote; \
	static uint32_t name##last_sleep_set_vote; \
	static struct rpm_clk name = { \
		.rpm_res_type = (type), \
		.rpm_clk_id = (r_id), \
@@ -68,6 +85,8 @@ extern struct clk_rpmrs_data clk_rpmrs_data_smd;
		.rpm_key = (key), \
		.peer = &active, \
		.rpmrs_data = (rpmrsdata),\
		.last_active_set_vote = &name##last_active_set_vote, \
		.last_sleep_set_vote = &name##last_sleep_set_vote, \
		.c = { \
			.ops = &clk_ops_rpm, \
			.dbg_name = #name, \
@@ -83,6 +102,8 @@ extern struct clk_rpmrs_data clk_rpmrs_data_smd;
		.peer = &name, \
		.active_only = true, \
		.rpmrs_data = (rpmrsdata),\
		.last_active_set_vote = &name##last_active_set_vote, \
		.last_sleep_set_vote = &name##last_sleep_set_vote, \
		.c = { \
			.ops = &clk_ops_rpm, \
			.dbg_name = #active, \
@@ -94,6 +115,8 @@ extern struct clk_rpmrs_data clk_rpmrs_data_smd;
#define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \
					key, rpmrsdata) \
	static struct rpm_clk active; \
	static uint32_t name##last_active_set_vote; \
	static uint32_t name##last_sleep_set_vote; \
	static struct rpm_clk name = { \
		.rpm_res_type = (type), \
		.rpm_clk_id = (r_id), \
@@ -102,6 +125,8 @@ extern struct clk_rpmrs_data clk_rpmrs_data_smd;
		.peer = &active, \
		.branch = true, \
		.rpmrs_data = (rpmrsdata),\
		.last_active_set_vote = &name##last_active_set_vote, \
		.last_sleep_set_vote = &name##last_sleep_set_vote, \
		.c = { \
			.ops = &clk_ops_rpm_branch, \
			.dbg_name = #name, \
@@ -118,6 +143,8 @@ extern struct clk_rpmrs_data clk_rpmrs_data_smd;
		.active_only = true, \
		.branch = true, \
		.rpmrs_data = (rpmrsdata),\
		.last_active_set_vote = &name##last_active_set_vote, \
		.last_sleep_set_vote = &name##last_sleep_set_vote, \
		.c = { \
			.ops = &clk_ops_rpm_branch, \
			.dbg_name = #active, \