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 45static 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 */ 55void 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 101int powersave_nap; 102 103#ifdef CONFIG_SYSCTL 104/* 105 * Register the sysctl to set/clear powersave_nap. 106 */ 107static 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}; 118static 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 128static int __init 129register_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