[PATCH 07/12] ARM: OMAP2+: powerdomain: cache the powerdomain next power state

Paul Walmsley paul at pwsan.com
Sun Dec 9 15:03:26 EST 2012


Cache the powerdomain next power state registers.  The objective here
is to avoid unneeded reads and writes to the next power state
registers, which are slow compared to RAM & CPU cache.

Signed-off-by: Paul Walmsley <paul at pwsan.com>
Cc: Kevin Hilman <khilman at deeprootsystems.com>
---
 arch/arm/mach-omap2/powerdomain.c |   64 +++++++++++++++++--------------------
 arch/arm/mach-omap2/powerdomain.h |   17 ++++++++++
 2 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 62e2f75..425c868 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -376,7 +376,7 @@ static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
  * software-controllable, returns 0; otherwise, passes along the
  * return value from pwrdm_set_logic_retst() if there is an error
  * returned by that function, otherwise, passes along the return value
- * from pwrdm_set_next_pwrst()
+ * from pwrdm_set_next_fpwrst()
  */
 static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
 					    u8 logic, u8 pwrst)
@@ -426,6 +426,9 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 	int next_pwrst, next_logic, ret;
 	u8 fpwrst;
 
+	if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID)
+		return pwrdm->next_fpwrst;
+
 	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
 	if (next_pwrst < 0)
 		return next_pwrst;
@@ -438,6 +441,10 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 			return next_logic;
 	}
 	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+	if (!ret) {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 
 	return (ret) ? ret : fpwrst;
 }
@@ -663,7 +670,7 @@ static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
  */
 static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 {
-	int prev, next, fpwrst;
+	int prev, fpwrst;
 	int trace_state = 0;
 
 	prev = _pwrdm_read_prev_fpwrst(pwrdm);
@@ -676,10 +683,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	 * If the power domain did not hit the desired state,
 	 * generate a trace event with both the desired and hit states
 	 */
-	next = _pwrdm_read_next_fpwrst(pwrdm);
-	if (next != prev) {
-		trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 |
-			       prev);
+	if (pwrdm->next_fpwrst != prev) {
+		trace_state = (PWRDM_TRACE_STATES_FLAG |
+			       pwrdm->next_fpwrst << 8 | prev);
 		trace_power_domain_target(pwrdm->name, trace_state,
 					  smp_processor_id());
 	}
@@ -1256,6 +1262,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
 	if (ret)
 		return ret;
 
+	if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID &&
+	    pwrdm->next_fpwrst == fpwrst)
+		return 0;
+
 	pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
 		 pwrdm->name);
 
@@ -1264,6 +1274,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
 
 	pwrdm_lock(pwrdm);
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	if (!ret) {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 	pwrdm_unlock(pwrdm);
 
 	return ret;
@@ -1279,36 +1293,16 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
  */
 int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 {
-	int next_pwrst, next_logic, ret;
-	u8 fpwrst;
+	int ret;
 
-	if (!arch_pwrdm)
+	if (!pwrdm)
 		return -EINVAL;
 
 	pwrdm_lock(pwrdm);
-
-	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst < 0) {
-		ret = next_pwrst;
-		goto prnf_out;
-	}
-
-	next_logic = next_pwrst;
-	if (_pwrdm_logic_retst_can_change(pwrdm) &&
-	    arch_pwrdm->pwrdm_read_logic_pwrst) {
-		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
-		if (next_logic < 0) {
-			ret = next_logic;
-			goto prnf_out;
-		}
-	}
-
-	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
-
-prnf_out:
+	ret = _pwrdm_read_next_fpwrst(pwrdm);
 	pwrdm_unlock(pwrdm);
 
-	return (ret) ? ret : fpwrst;
+	return ret;
 }
 
 /**
@@ -1344,10 +1338,6 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 
 	pwrdm_lock(pwrdm);
 
-	/*
-	 * XXX quite heavyweight for what this is intended to do; the
-	 * next fpwrst should simply be cached
-	 */
 	next_fpwrst = _pwrdm_read_next_fpwrst(pwrdm);
 	if (next_fpwrst == fpwrst)
 		goto psf_out;
@@ -1364,9 +1354,13 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 	}
 
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
-	if (ret)
+	if (ret) {
 		pr_err("%s: unable to set power state of powerdomain: %s\n",
 		       __func__, pwrdm->name);
+	} else {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 
 	_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
 
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index c19bdc3..1fb21f5 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -84,6 +84,16 @@ enum pwrdm_func_state {
 #define PWRDM_HAS_LOWPOWERSTATECHANGE	BIT(2)
 
 /*
+ * Powerdomain internal flags (struct powerdomain._flags)
+ *
+ * _PWRDM_NEXT_FPWRST_IS_VALID: the locally-cached copy of the
+ *    powerdomain's next-functional-power-state -- struct
+ *    powerdomain.next_fpwrst -- is valid.  If this bit is not set,
+ *    the code needs to load the current value from the hardware.
+ */
+#define _PWRDM_NEXT_FPWRST_IS_VALID	BIT(0)
+
+/*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
  * maximum is 5.
  */
@@ -127,12 +137,17 @@ struct powerdomain;
  *	in @pwrstctrl_offs
  * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans)
  * @fpwrst_counter: estimated number of times the pwrdm entered the power states
+ * @next_fpwrst: cache of the powerdomain's next-power-state
  * @timer: sched_clock() timestamp of last pwrdm_state_switch()
  * @fpwrst_timer: estimated nanoseconds of residency in the various power states
  * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
  * @_lock_flags: stored flags when @_lock is taken
+ * @_flags: flags (for internal use only)
  *
  * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
+ *
+ * Possible values for @_flags are documented above in the
+ * "Powerdomain internal flags (struct powerdomain._flags)" comments.
  */
 struct powerdomain {
 	const char *name;
@@ -149,6 +164,8 @@ struct powerdomain {
 	const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
 	const u8 prcm_partition;
 	u8 fpwrst;
+	u8 next_fpwrst;
+	u8 _flags;
 	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
 	struct list_head node;
 	struct list_head voltdm_node;





More information about the linux-arm-kernel mailing list