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 <[email protected]>
Cc: Kevin Hilman <[email protected]>
---
 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;


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to