diff options
Diffstat (limited to 'kernel/sched/idle.c')
| -rw-r--r-- | kernel/sched/idle.c | 114 | 
1 files changed, 59 insertions, 55 deletions
| diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index fefcb1fa5160..594275ed2620 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -15,6 +15,15 @@  #include "sched.h" +/** + * sched_idle_set_state - Record idle state for the current CPU. + * @idle_state: State to record. + */ +void sched_idle_set_state(struct cpuidle_state *idle_state) +{ +	idle_set_state(this_rq(), idle_state); +} +  static int __read_mostly cpu_idle_force_poll;  void cpu_idle_poll_ctrl(bool enable) @@ -68,6 +77,46 @@ void __weak arch_cpu_idle(void)  }  /** + * default_idle_call - Default CPU idle routine. + * + * To use when the cpuidle framework cannot be used. + */ +void default_idle_call(void) +{ +	if (current_clr_polling_and_test()) +		local_irq_enable(); +	else +		arch_cpu_idle(); +} + +static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev, +		      int next_state) +{ +	/* Fall back to the default arch idle method on errors. */ +	if (next_state < 0) { +		default_idle_call(); +		return next_state; +	} + +	/* +	 * The idle task must be scheduled, it is pointless to go to idle, just +	 * update no idle residency and return. +	 */ +	if (current_clr_polling_and_test()) { +		dev->last_residency = 0; +		local_irq_enable(); +		return -EBUSY; +	} + +	/* +	 * Enter the idle state previously returned by the governor decision. +	 * This function will block until an interrupt occurs and will take +	 * care of re-enabling the local interrupts +	 */ +	return cpuidle_enter(drv, dev, next_state); +} + +/**   * cpuidle_idle_call - the main idle function   *   * NOTE: no locks or semaphores should be used here @@ -81,7 +130,6 @@ static void cpuidle_idle_call(void)  	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);  	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);  	int next_state, entered_state; -	bool reflect;  	/*  	 * Check if the idle task must be rescheduled. If it is the @@ -105,8 +153,10 @@ static void cpuidle_idle_call(void)  	 */  	rcu_idle_enter(); -	if (cpuidle_not_available(drv, dev)) -		goto use_default; +	if (cpuidle_not_available(drv, dev)) { +		default_idle_call(); +		goto exit_idle; +	}  	/*  	 * Suspend-to-idle ("freeze") is a system state in which all user space @@ -124,52 +174,19 @@ static void cpuidle_idle_call(void)  			goto exit_idle;  		} -		reflect = false;  		next_state = cpuidle_find_deepest_state(drv, dev); +		call_cpuidle(drv, dev, next_state);  	} else { -		reflect = true;  		/*  		 * Ask the cpuidle framework to choose a convenient idle state.  		 */  		next_state = cpuidle_select(drv, dev); -	} -	/* Fall back to the default arch idle method on errors. */ -	if (next_state < 0) -		goto use_default; - -	/* -	 * The idle task must be scheduled, it is pointless to -	 * go to idle, just update no idle residency and get -	 * out of this function -	 */ -	if (current_clr_polling_and_test()) { -		dev->last_residency = 0; -		entered_state = next_state; -		local_irq_enable(); -		goto exit_idle; -	} - -	/* Take note of the planned idle state. */ -	idle_set_state(this_rq(), &drv->states[next_state]); - -	/* -	 * Enter the idle state previously returned by the governor decision. -	 * This function will block until an interrupt occurs and will take -	 * care of re-enabling the local interrupts -	 */ -	entered_state = cpuidle_enter(drv, dev, next_state); - -	/* The cpu is no longer idle or about to enter idle. */ -	idle_set_state(this_rq(), NULL); - -	if (entered_state == -EBUSY) -		goto use_default; - -	/* -	 * Give the governor an opportunity to reflect on the outcome -	 */ -	if (reflect) +		entered_state = call_cpuidle(drv, dev, next_state); +		/* +		 * Give the governor an opportunity to reflect on the outcome +		 */  		cpuidle_reflect(dev, entered_state); +	}  exit_idle:  	__current_set_polling(); @@ -182,19 +199,6 @@ exit_idle:  	rcu_idle_exit();  	start_critical_timings(); -	return; - -use_default: -	/* -	 * We can't use the cpuidle framework, let's use the default -	 * idle routine. -	 */ -	if (current_clr_polling_and_test()) -		local_irq_enable(); -	else -		arch_cpu_idle(); - -	goto exit_idle;  }  DEFINE_PER_CPU(bool, cpu_dead_idle); |