Re: [PATCH 03/10] OMAP3: PM: move device-specific special cases from PM core into CPUidle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> writes:

> Paul Walmsley <paul@xxxxxxxxx> writes:
>
>> Hi Kevin
>>
>> On Tue, 21 Sep 2010, Kevin Hilman wrote:
>>
>>> Paul Walmsley <paul@xxxxxxxxx> writes:
>>> 
>>> > On Wed, 15 Sep 2010, Kevin Hilman wrote:
>>> >
>>> >> In an effort to simplify the core idle path, move any device-specific
>>> >> special case handling from the core PM idle path into the CPUidle
>>> >> pre-idle checking path.
>>> >
>>> > As with the original patch, I don't quite understand the improvement 
>>> > here.  In particular, this part:
>>> >
>>> >> diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
>>> >> index 3d3d035..0923b82 100644
>>> >> --- a/arch/arm/mach-omap2/cpuidle34xx.c
>>> >> +++ b/arch/arm/mach-omap2/cpuidle34xx.c
>>> >> @@ -233,14 +234,54 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
>>> >>  			       struct cpuidle_state *state)
>>> >>  {
>>> >>  	struct cpuidle_state *new_state = next_valid_state(dev, state);
>>> >> +	u32 core_next_state, per_next_state = 0, per_saved_state = 0;
>>> >> +	u32 cam_state;
>>> >> +	struct omap3_processor_cx *cx;
>>> >> +	int ret;
>>> >>  
>>> >>  	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
>>> >>  		BUG_ON(!dev->safe_state);
>>> >>  		new_state = dev->safe_state;
>>> >> +		goto select_state;
>>> >> +	}
>>> >> +
>>> >> +	cx = cpuidle_get_statedata(state);
>>> >> +	core_next_state = cx->core_state;
>>> >> +
>>> >> +	/*
>>> >> +	 * Prevent idle completely if CAM is active.
>>> >> +	 * CAM does not have wakeup capability in OMAP3.
>>> >> +	 */
>>> >> +	cam_state = pwrdm_read_pwrst(cam_pd);
>>> >> +	if (cam_state == PWRDM_POWER_ON) {
>>> >> +		new_state = dev->safe_state;
>>> >> +		goto select_state;
>>> >>  	}
>>> >>  
>>> >> +	/*
>>> >> +	 * Prevent PER off if CORE is not in retention or off as this
>>> >> +	 * would disable PER wakeups completely.
>>> >> +	 */
>>> >> +	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
>>> >> +	if ((per_next_state == PWRDM_POWER_OFF) &&
>>> >> +	    (core_next_state > PWRDM_POWER_RET)) {
>>> >> +		per_next_state = PWRDM_POWER_RET;
>>> >> +		pwrdm_set_next_pwrst(per_pd, per_next_state);
>>> >> +	}
>>> >> +
>>> >> +	/* Are we changing PER target state? */
>>> >> +	if (per_next_state != per_saved_state)
>>> >> +		pwrdm_set_next_pwrst(per_pd, per_next_state);
>>> >
>>> > In this case, the PER / CORE constraints don't have anything to do with 
>>> > the MPU or CPUIdle, so they don't seem to belong in the CPUIdle code.  The 
>>> > extra comments are certainly nice -- they make it more clear as to what is 
>>> > going on here -- but maybe those can just be added to pm34xx.c ?
>>> 
>>> CPUidle currently manages MPU and CORE powerdomains, so the CORE
>>> constraints seem to make perfect sense here (at least to me.)
>>
>> I do mean CORE also -- basically, anything that is not the CPU.  IMHO 
>> CPUIdle shouldn't manage CORE directly since it's not part of the CPU.  
>> Also since OMAPs have other processors (e.g., DSP, DMA, etc) that can use 
>> the CORE independently of the CPU's power state, it doesn't make sense for 
>> that code to live inside CPUIdle -- probably it should live in some type 
>> of SystemIdle, CORE powerdomain idle or L3 idle.  Again IMHO, the C states 
>> should only represent the MPU's idle state.
>>
>>> The question is probably more about the PER constraints.
>>> 
>>> The basic goal of this is to streamline the core idle (omap_sram_idle())
>>> to be the minimum streamline idle, and to move all the constraint
>>> checking and activity checking to higher layers (like CPUidle.)
>>> Specifically, I'm working towards moving the device-specific idle
>>> constraints out of the core idle path (omap_sram_idle()) and move them
>>> into higher layers where we're checking for activity etc.
>>> 
>>> This is just a baby step towards moving the device-idle out of CPUidle
>>> completely to a place where it can be managed by the driver themeselves
>>> using runtime PM or by using constraints instead of these hard-coded
>>> hacks.
>>
>> I agree completely with the goal; it's the implementation that I don't 
>> like ;-)  But if you agree with the basic idea, that CORE / PER / 
>> whatever-idle should ultimately go elsewhere, since I don't have time to 
>> come up with a constructive alternative at the moment, would you be 
>> willing to just drop a FIXME comment in that code, near the CAM and the 
>> PER / CORE stuff, that mentions that that code should ultimately be 
>> segmented out into its own idle code?
>
> Absolutely...  will do.
>

Here's an updated patch, which will be included in the forthcoming
pm-next pull request.  I updated the changelog with a 'NOTE' and also
added a FIXME in the code.

Thanks for the feedback Paul.

Kevin


>From e7410cf7831c2e5106a90dac6179df5d2c9bd60e Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 8 Sep 2010 16:37:42 -0700
Subject: [PATCH 03/13] OMAP3: PM: move device-specific special cases from PM core into CPUidle

In an effort to simplify the core idle path, move any device-specific
special case handling from the core PM idle path into the CPUidle
pre-idle checking path.

This keeps the core, interrupts-disabled idle path streamlined and
independent of any device-specific handling, and also allows CPUidle
to do the checking only for certain C-states as needed.  This patch
has the device checks in place for all states with the CHECK_BM flag,
namely all states >= C2.

This patch was inspired by a similar patch written by Tero Kristo as
part of a larger series to add INACTIVE state support.

NOTE: This is a baby-step towards decoupling device idle (or system
idle) from CPU idle.  Eventually, CPUidle should only manage the CPU,
and device/system idle should be managed elsewhere.

Cc: Tero Kristo <tero.kristo@xxxxxxxxx>
Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
---
 arch/arm/mach-omap2/cpuidle34xx.c |   58 +++++++++++++++++++++++++++++++++++--
 arch/arm/mach-omap2/pm34xx.c      |   14 +--------
 2 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 3d3d035..8ea012e 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -60,7 +60,8 @@ struct omap3_processor_cx {
 
 struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
 struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *cam_pd;
 
 /*
  * The latencies/thresholds for various C states have
@@ -233,14 +234,62 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 			       struct cpuidle_state *state)
 {
 	struct cpuidle_state *new_state = next_valid_state(dev, state);
+	u32 core_next_state, per_next_state = 0, per_saved_state = 0;
+	u32 cam_state;
+	struct omap3_processor_cx *cx;
+	int ret;
 
 	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
 		BUG_ON(!dev->safe_state);
 		new_state = dev->safe_state;
+		goto select_state;
+	}
+
+	cx = cpuidle_get_statedata(state);
+	core_next_state = cx->core_state;
+
+	/*
+	 * FIXME: we currently manage device-specific idle states
+	 *        for PER and CORE in combination with CPU-specific
+	 *        idle states.  This is wrong, and device-specific
+	 *        idle managment needs to be separated out into 
+	 *        its own code.
+	 */
+
+	/*
+	 * Prevent idle completely if CAM is active.
+	 * CAM does not have wakeup capability in OMAP3.
+	 */
+	cam_state = pwrdm_read_pwrst(cam_pd);
+	if (cam_state == PWRDM_POWER_ON) {
+		new_state = dev->safe_state;
+		goto select_state;
+	}
+
+	/*
+	 * Prevent PER off if CORE is not in retention or off as this
+	 * would disable PER wakeups completely.
+	 */
+	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
+	if ((per_next_state == PWRDM_POWER_OFF) &&
+	    (core_next_state > PWRDM_POWER_RET)) {
+		per_next_state = PWRDM_POWER_RET;
+		pwrdm_set_next_pwrst(per_pd, per_next_state);
 	}
 
+	/* Are we changing PER target state? */
+	if (per_next_state != per_saved_state)
+		pwrdm_set_next_pwrst(per_pd, per_next_state);
+
+select_state:
 	dev->last_state = new_state;
-	return omap3_enter_idle(dev, new_state);
+	ret = omap3_enter_idle(dev, new_state);
+
+	/* Restore original PER state if it was modified */
+	if (per_next_state != per_saved_state)
+		pwrdm_set_next_pwrst(per_pd, per_saved_state);
+
+	return ret;
 }
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -328,7 +377,8 @@ void omap_init_power_states(void)
 			cpuidle_params_table[OMAP3_STATE_C2].threshold;
 	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_CHECK_BM;
 
 	/* C3 . MPU CSWR + Core inactive */
 	omap3_power_states[OMAP3_STATE_C3].valid =
@@ -426,6 +476,8 @@ int __init omap3_idle_init(void)
 
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
 	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	cam_pd = pwrdm_lookup("cam_pwrdm");
 
 	omap_init_power_states();
 	cpuidle_register_driver(&omap3_idle_driver);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 429268e..bb2ba1e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -346,7 +346,6 @@ void omap_sram_idle(void)
 	int core_next_state = PWRDM_POWER_ON;
 	int core_prev_state, per_prev_state;
 	u32 sdrc_pwr = 0;
-	int per_state_modified = 0;
 
 	if (!_omap_sram_idle)
 		return;
@@ -391,19 +390,10 @@ void omap_sram_idle(void)
 	if (per_next_state < PWRDM_POWER_ON) {
 		omap_uart_prepare_idle(2);
 		omap2_gpio_prepare_for_idle(per_next_state);
-		if (per_next_state == PWRDM_POWER_OFF) {
-			if (core_next_state == PWRDM_POWER_ON) {
-				per_next_state = PWRDM_POWER_RET;
-				pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
-				per_state_modified = 1;
-			} else
+		if (per_next_state == PWRDM_POWER_OFF)
 				omap3_per_save_context();
-		}
 	}
 
-	if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
-		omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
-
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
 		omap_uart_prepare_idle(0);
@@ -470,8 +460,6 @@ void omap_sram_idle(void)
 		if (per_prev_state == PWRDM_POWER_OFF)
 			omap3_per_restore_context();
 		omap_uart_resume_idle(2);
-		if (per_state_modified)
-			pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
 	}
 
 	/* Disable IO-PAD and IO-CHAIN wakeup */
-- 
1.7.2.1


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


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux