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 28 #include <asm/system.h> 29 #include <asm/processor.h> 30 #include <asm/cputable.h> 31 #include <asm/time.h> 32 #include <asm/machdep.h> 33 #include <asm/smp.h> 34 35 #ifdef CONFIG_HOTPLUG_CPU 36 /* this is used for software suspend, and that shuts down 37 * CPUs even while the system is still booting... */ 38 #define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ 39 (system_state == SYSTEM_RUNNING \ 40 || system_state == SYSTEM_BOOTING)) 41 #else 42 #define cpu_should_die() 0 43 #endif 44 45 static int __init powersave_off(char *arg) 46 { 47 ppc_md.power_save = NULL; 48 return 0; 49 } 50 __setup("powersave=off", powersave_off); 51 52 /* 53 * The body of the idle task. 54 */ 55 void cpu_idle(void) 56 { 57 if (ppc_md.idle_loop) 58 ppc_md.idle_loop(); /* doesn't return */ 59 60 set_thread_flag(TIF_POLLING_NRFLAG); 61 while (1) { 62 while (!need_resched() && !cpu_should_die()) { 63 ppc64_runlatch_off(); 64 65 if (ppc_md.power_save) { 66 clear_thread_flag(TIF_POLLING_NRFLAG); 67 /* 68 * smp_mb is so clearing of TIF_POLLING_NRFLAG 69 * is ordered w.r.t. need_resched() test. 70 */ 71 smp_mb(); 72 local_irq_disable(); 73 74 /* check again after disabling irqs */ 75 if (!need_resched() && !cpu_should_die()) 76 ppc_md.power_save(); 77 78 local_irq_enable(); 79 set_thread_flag(TIF_POLLING_NRFLAG); 80 81 } else { 82 /* 83 * Go into low thread priority and possibly 84 * low power mode. 85 */ 86 HMT_low(); 87 HMT_very_low(); 88 } 89 } 90 91 HMT_medium(); 92 ppc64_runlatch_on(); 93 if (cpu_should_die()) 94 cpu_die(); 95 preempt_enable_no_resched(); 96 schedule(); 97 preempt_disable(); 98 } 99 } 100 101 int powersave_nap; 102 103 #ifdef CONFIG_SYSCTL 104 /* 105 * Register the sysctl to set/clear powersave_nap. 106 */ 107 static ctl_table powersave_nap_ctl_table[]={ 108 { 109 .ctl_name = KERN_PPC_POWERSAVE_NAP, 110 .procname = "powersave-nap", 111 .data = &powersave_nap, 112 .maxlen = sizeof(int), 113 .mode = 0644, 114 .proc_handler = &proc_dointvec, 115 }, 116 {} 117 }; 118 static ctl_table powersave_nap_sysctl_root[] = { 119 { 120 .ctl_name = CTL_KERN, 121 .procname = "kernel", 122 .mode = 0755, 123 .child = powersave_nap_ctl_table, 124 }, 125 {} 126 }; 127 128 static int __init 129 register_powersave_nap_sysctl(void) 130 { 131 register_sysctl_table(powersave_nap_sysctl_root); 132 133 return 0; 134 } 135 __initcall(register_powersave_nap_sysctl); 136 #endif 137