1 /* 2 * Idle daemon for PowerPC. Idle daemon will handle any action 3 * that needs to be taken when the system becomes idle. 4 * 5 * Originally written by Cort Dougan (cort@cs.nmt.edu). 6 * Subsequent 32-bit hacking by Tom Rini, Armin Kuster, 7 * Paul Mackerras and others. 8 * 9 * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com> 10 * 11 * Additional shared processor, SMT, and firmware support 12 * Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com> 13 * 14 * 32-bit and 64-bit versions merged by Paul Mackerras <paulus@samba.org> 15 * 16 * This program is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU General Public License 18 * as published by the Free Software Foundation; either version 19 * 2 of the License, or (at your option) any later version. 20 */ 21 22 #include <linux/sched.h> 23 #include <linux/kernel.h> 24 #include <linux/smp.h> 25 #include <linux/cpu.h> 26 #include <linux/sysctl.h> 27 #include <linux/tick.h> 28 29 #include <asm/system.h> 30 #include <asm/processor.h> 31 #include <asm/cputable.h> 32 #include <asm/time.h> 33 #include <asm/machdep.h> 34 #include <asm/smp.h> 35 36 #ifdef CONFIG_HOTPLUG_CPU 37 #define cpu_should_die() cpu_is_offline(smp_processor_id()) 38 #else 39 #define cpu_should_die() 0 40 #endif 41 42 unsigned long cpuidle_disable = IDLE_NO_OVERRIDE; 43 EXPORT_SYMBOL(cpuidle_disable); 44 45 static int __init powersave_off(char *arg) 46 { 47 ppc_md.power_save = NULL; 48 cpuidle_disable = IDLE_POWERSAVE_OFF; 49 return 0; 50 } 51 __setup("powersave=off", powersave_off); 52 53 #if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_TRACEPOINTS) 54 static const bool idle_uses_rcu = 1; 55 #else 56 static const bool idle_uses_rcu; 57 #endif 58 59 /* 60 * The body of the idle task. 61 */ 62 void cpu_idle(void) 63 { 64 if (ppc_md.idle_loop) 65 ppc_md.idle_loop(); /* doesn't return */ 66 67 set_thread_flag(TIF_POLLING_NRFLAG); 68 while (1) { 69 tick_nohz_idle_enter(); 70 if (!idle_uses_rcu) 71 rcu_idle_enter(); 72 73 while (!need_resched() && !cpu_should_die()) { 74 ppc64_runlatch_off(); 75 76 if (ppc_md.power_save) { 77 clear_thread_flag(TIF_POLLING_NRFLAG); 78 /* 79 * smp_mb is so clearing of TIF_POLLING_NRFLAG 80 * is ordered w.r.t. need_resched() test. 81 */ 82 smp_mb(); 83 local_irq_disable(); 84 85 /* Don't trace irqs off for idle */ 86 stop_critical_timings(); 87 88 /* check again after disabling irqs */ 89 if (!need_resched() && !cpu_should_die()) 90 ppc_md.power_save(); 91 92 start_critical_timings(); 93 94 local_irq_enable(); 95 set_thread_flag(TIF_POLLING_NRFLAG); 96 97 } else { 98 /* 99 * Go into low thread priority and possibly 100 * low power mode. 101 */ 102 HMT_low(); 103 HMT_very_low(); 104 } 105 } 106 107 HMT_medium(); 108 ppc64_runlatch_on(); 109 if (!idle_uses_rcu) 110 rcu_idle_exit(); 111 tick_nohz_idle_exit(); 112 preempt_enable_no_resched(); 113 if (cpu_should_die()) 114 cpu_die(); 115 schedule(); 116 preempt_disable(); 117 } 118 } 119 120 121 /* 122 * cpu_idle_wait - Used to ensure that all the CPUs come out of the old 123 * idle loop and start using the new idle loop. 124 * Required while changing idle handler on SMP systems. 125 * Caller must have changed idle handler to the new value before the call. 126 * This window may be larger on shared systems. 127 */ 128 void cpu_idle_wait(void) 129 { 130 int cpu; 131 smp_mb(); 132 133 /* kick all the CPUs so that they exit out of old idle routine */ 134 get_online_cpus(); 135 for_each_online_cpu(cpu) { 136 if (cpu != smp_processor_id()) 137 smp_send_reschedule(cpu); 138 } 139 put_online_cpus(); 140 } 141 EXPORT_SYMBOL_GPL(cpu_idle_wait); 142 143 int powersave_nap; 144 145 #ifdef CONFIG_SYSCTL 146 /* 147 * Register the sysctl to set/clear powersave_nap. 148 */ 149 static ctl_table powersave_nap_ctl_table[]={ 150 { 151 .procname = "powersave-nap", 152 .data = &powersave_nap, 153 .maxlen = sizeof(int), 154 .mode = 0644, 155 .proc_handler = proc_dointvec, 156 }, 157 {} 158 }; 159 static ctl_table powersave_nap_sysctl_root[] = { 160 { 161 .procname = "kernel", 162 .mode = 0555, 163 .child = powersave_nap_ctl_table, 164 }, 165 {} 166 }; 167 168 static int __init 169 register_powersave_nap_sysctl(void) 170 { 171 register_sysctl_table(powersave_nap_sysctl_root); 172 173 return 0; 174 } 175 __initcall(register_powersave_nap_sysctl); 176 #endif 177