idle.c 3.3 KB
Newer Older
1 2 3
/*
 * The idle loop for all SuperH platforms.
 *
4
 *  Copyright (C) 2002 - 2009  Paul Mundt
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/tick.h>
#include <linux/preempt.h>
#include <linux/thread_info.h>
#include <linux/irqflags.h>
18
#include <linux/smp.h>
L
Len Brown 已提交
19
#include <linux/cpuidle.h>
20 21
#include <asm/pgalloc.h>
#include <asm/system.h>
A
Arun Sharma 已提交
22
#include <linux/atomic.h>
P
Paul Mundt 已提交
23
#include <asm/smp.h>
24

25
void (*pm_idle)(void);
26 27

static int hlt_counter;
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

static int __init nohlt_setup(char *__unused)
{
	hlt_counter = 1;
	return 1;
}
__setup("nohlt", nohlt_setup);

static int __init hlt_setup(char *__unused)
{
	hlt_counter = 0;
	return 1;
}
__setup("hlt", hlt_setup);

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
static inline int hlt_works(void)
{
	return !hlt_counter;
}

/*
 * On SMP it's slightly faster (but much more power-consuming!)
 * to poll the ->work.need_resched flag instead of waiting for the
 * cross-CPU IPI to arrive. Use this option with caution.
 */
static void poll_idle(void)
{
	local_irq_enable();
	while (!need_resched())
		cpu_relax();
}

60
void default_idle(void)
61
{
62
	if (hlt_works()) {
63 64 65
		clear_thread_flag(TIF_POLLING_NRFLAG);
		smp_mb__after_clear_bit();

66
		set_bl_bit();
67 68
		if (!need_resched()) {
			local_irq_enable();
69
			cpu_sleep();
70 71
		} else
			local_irq_enable();
72 73

		set_thread_flag(TIF_POLLING_NRFLAG);
74
		clear_bl_bit();
75
	} else
76
		poll_idle();
77 78
}

79 80 81 82 83
/*
 * The idle thread. There's no useful work to be done, so just try to conserve
 * power and have a low exit latency (ie sit in a loop waiting for somebody to
 * say that they'd like to reschedule)
 */
84 85
void cpu_idle(void)
{
86 87
	unsigned int cpu = smp_processor_id();

88 89 90 91
	set_thread_flag(TIF_POLLING_NRFLAG);

	/* endless idle loop with no priority at all */
	while (1) {
92 93
		tick_nohz_idle_enter();
		rcu_idle_enter();
94

P
Paul Mundt 已提交
95
		while (!need_resched()) {
96 97 98
			check_pgt_cache();
			rmb();

P
Paul Mundt 已提交
99 100 101
			if (cpu_is_offline(cpu))
				play_dead();

102 103 104
			local_irq_disable();
			/* Don't trace irqs off for idle */
			stop_critical_timings();
105
			if (cpuidle_idle_call())
L
Len Brown 已提交
106
				pm_idle();
107 108 109 110 111 112 113
			/*
			 * Sanity check to ensure that pm_idle() returns
			 * with IRQs enabled
			 */
			WARN_ON(irqs_disabled());
			start_critical_timings();
		}
114

115 116
		rcu_idle_exit();
		tick_nohz_idle_exit();
117
		schedule_preempt_disabled();
118 119
	}
}
120

121
void __init select_idle_routine(void)
122 123 124 125 126 127 128 129 130 131 132 133 134
{
	/*
	 * If a platform has set its own idle routine, leave it alone.
	 */
	if (pm_idle)
		return;

	if (hlt_works())
		pm_idle = default_idle;
	else
		pm_idle = poll_idle;
}

135 136 137 138
static void do_nothing(void *unused)
{
}

139 140 141
void stop_this_cpu(void *unused)
{
	local_irq_disable();
142
	set_cpu_online(smp_processor_id(), false);
143 144 145 146 147

	for (;;)
		cpu_sleep();
}

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
/*
 * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
 * pm_idle and update to new pm_idle value. Required while changing pm_idle
 * handler on SMP systems.
 *
 * Caller must have changed pm_idle to the new value before the call. Old
 * pm_idle value will not be used by any CPU after the return of this function.
 */
void cpu_idle_wait(void)
{
	smp_mb();
	/* kick all the CPUs so that they exit out of pm_idle */
	smp_call_function(do_nothing, NULL, 1);
}
EXPORT_SYMBOL_GPL(cpu_idle_wait);