瀏覽代碼

Merge branch 'pm-cpuidle'

* pm-cpuidle:
  cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state
Rafael J. Wysocki 10 年之前
父節點
當前提交
d461003574
共有 2 個文件被更改,包括 23 次插入0 次删除
  1. 12 0
      drivers/cpuidle/cpuidle-powernv.c
  2. 11 0
      drivers/cpuidle/cpuidle-pseries.c

+ 12 - 0
drivers/cpuidle/cpuidle-powernv.c

@@ -29,18 +29,25 @@ struct cpuidle_driver powernv_idle_driver = {
 
 
 static int max_idle_state;
 static int max_idle_state;
 static struct cpuidle_state *cpuidle_state_table;
 static struct cpuidle_state *cpuidle_state_table;
+static u64 snooze_timeout;
+static bool snooze_timeout_en;
 
 
 static int snooze_loop(struct cpuidle_device *dev,
 static int snooze_loop(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			struct cpuidle_driver *drv,
 			int index)
 			int index)
 {
 {
+	u64 snooze_exit_time;
+
 	local_irq_enable();
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
 
+	snooze_exit_time = get_tb() + snooze_timeout;
 	ppc64_runlatch_off();
 	ppc64_runlatch_off();
 	while (!need_resched()) {
 	while (!need_resched()) {
 		HMT_low();
 		HMT_low();
 		HMT_very_low();
 		HMT_very_low();
+		if (snooze_timeout_en && get_tb() > snooze_exit_time)
+			break;
 	}
 	}
 
 
 	HMT_medium();
 	HMT_medium();
@@ -252,6 +259,11 @@ static int powernv_idle_probe(void)
 		cpuidle_state_table = powernv_states;
 		cpuidle_state_table = powernv_states;
 		/* Device tree can indicate more idle states */
 		/* Device tree can indicate more idle states */
 		max_idle_state = powernv_add_idle_states();
 		max_idle_state = powernv_add_idle_states();
+		if (max_idle_state > 1) {
+			snooze_timeout_en = true;
+			snooze_timeout = powernv_states[1].target_residency *
+					 tb_ticks_per_usec;
+		}
  	} else
  	} else
  		return -ENODEV;
  		return -ENODEV;
 
 

+ 11 - 0
drivers/cpuidle/cpuidle-pseries.c

@@ -27,6 +27,8 @@ struct cpuidle_driver pseries_idle_driver = {
 
 
 static int max_idle_state;
 static int max_idle_state;
 static struct cpuidle_state *cpuidle_state_table;
 static struct cpuidle_state *cpuidle_state_table;
+static u64 snooze_timeout;
+static bool snooze_timeout_en;
 
 
 static inline void idle_loop_prolog(unsigned long *in_purr)
 static inline void idle_loop_prolog(unsigned long *in_purr)
 {
 {
@@ -58,14 +60,18 @@ static int snooze_loop(struct cpuidle_device *dev,
 			int index)
 			int index)
 {
 {
 	unsigned long in_purr;
 	unsigned long in_purr;
+	u64 snooze_exit_time;
 
 
 	idle_loop_prolog(&in_purr);
 	idle_loop_prolog(&in_purr);
 	local_irq_enable();
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 	set_thread_flag(TIF_POLLING_NRFLAG);
+	snooze_exit_time = get_tb() + snooze_timeout;
 
 
 	while (!need_resched()) {
 	while (!need_resched()) {
 		HMT_low();
 		HMT_low();
 		HMT_very_low();
 		HMT_very_low();
+		if (snooze_timeout_en && get_tb() > snooze_exit_time)
+			break;
 	}
 	}
 
 
 	HMT_medium();
 	HMT_medium();
@@ -244,6 +250,11 @@ static int pseries_idle_probe(void)
 	} else
 	} else
 		return -ENODEV;
 		return -ENODEV;
 
 
+	if (max_idle_state > 1) {
+		snooze_timeout_en = true;
+		snooze_timeout = cpuidle_state_table[1].target_residency *
+				 tb_ticks_per_usec;
+	}
 	return 0;
 	return 0;
 }
 }