2005-04-16 15:20:36 -07:00
/*
* Idle daemon for PowerPC . Idle daemon will handle any action
* that needs to be taken when the system becomes idle .
*
2006-03-27 15:03:03 +11:00
* Originally written by Cort Dougan ( cort @ cs . nmt . edu ) .
* Subsequent 32 - bit hacking by Tom Rini , Armin Kuster ,
* Paul Mackerras and others .
2005-04-16 15:20:36 -07:00
*
* iSeries supported added by Mike Corrigan < mikejc @ us . ibm . com >
*
* Additional shared processor , SMT , and firmware support
* Copyright ( c ) 2003 Dave Engebretsen < engebret @ us . ibm . com >
*
2006-03-27 15:03:03 +11:00
* 32 - bit and 64 - bit versions merged by Paul Mackerras < paulus @ samba . org >
*
2005-04-16 15:20:36 -07:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/smp.h>
# include <linux/cpu.h>
# include <linux/sysctl.h>
2007-09-21 13:26:03 +10:00
# include <linux/tick.h>
2005-04-16 15:20:36 -07:00
# include <asm/system.h>
# include <asm/processor.h>
# include <asm/cputable.h>
# include <asm/time.h>
2005-07-07 17:56:28 -07:00
# include <asm/machdep.h>
2005-11-07 13:18:13 +11:00
# include <asm/smp.h>
2005-04-16 15:20:36 -07:00
2006-03-27 15:03:03 +11:00
# ifdef CONFIG_HOTPLUG_CPU
2008-09-24 22:56:25 +00:00
# define cpu_should_die() cpu_is_offline(smp_processor_id())
2006-03-27 15:03:03 +11:00
# else
# define cpu_should_die() 0
# endif
2005-04-16 15:20:36 -07:00
2006-10-24 18:31:26 +02:00
static int __init powersave_off ( char * arg )
{
ppc_md . power_save = NULL ;
return 0 ;
}
__setup ( " powersave=off " , powersave_off ) ;
2006-03-27 15:03:03 +11:00
/*
* The body of the idle task .
*/
void cpu_idle ( void )
2005-04-16 15:20:36 -07:00
{
2006-03-27 15:03:03 +11:00
if ( ppc_md . idle_loop )
ppc_md . idle_loop ( ) ; /* doesn't return */
2005-04-16 15:20:36 -07:00
2006-03-27 15:03:03 +11:00
set_thread_flag ( TIF_POLLING_NRFLAG ) ;
2005-04-16 15:20:36 -07:00
while ( 1 ) {
2008-07-18 17:27:28 +02:00
tick_nohz_stop_sched_tick ( 1 ) ;
2006-03-27 15:03:03 +11:00
while ( ! need_resched ( ) & & ! cpu_should_die ( ) ) {
2006-04-02 19:54:09 +10:00
ppc64_runlatch_off ( ) ;
2006-03-27 15:03:03 +11:00
if ( ppc_md . power_save ) {
clear_thread_flag ( TIF_POLLING_NRFLAG ) ;
/*
* smp_mb is so clearing of TIF_POLLING_NRFLAG
* is ordered w . r . t . need_resched ( ) test .
*/
smp_mb ( ) ;
local_irq_disable ( ) ;
2008-11-14 16:21:19 -08:00
/* Don't trace irqs off for idle */
stop_critical_timings ( ) ;
2006-03-27 15:03:03 +11:00
/* check again after disabling irqs */
if ( ! need_resched ( ) & & ! cpu_should_die ( ) )
ppc_md . power_save ( ) ;
2008-11-14 16:21:19 -08:00
start_critical_timings ( ) ;
2006-03-27 15:03:03 +11:00
local_irq_enable ( ) ;
set_thread_flag ( TIF_POLLING_NRFLAG ) ;
} else {
2005-04-16 15:20:36 -07:00
/*
* Go into low thread priority and possibly
* low power mode .
*/
HMT_low ( ) ;
HMT_very_low ( ) ;
}
}
2006-03-27 15:03:03 +11:00
HMT_medium ( ) ;
2005-07-07 17:56:33 -07:00
ppc64_runlatch_on ( ) ;
2007-09-21 13:26:03 +10:00
tick_nohz_restart_sched_tick ( ) ;
2006-03-27 15:03:03 +11:00
if ( cpu_should_die ( ) )
cpu_die ( ) ;
2005-11-08 21:39:01 -08:00
preempt_enable_no_resched ( ) ;
2005-04-16 15:20:36 -07:00
schedule ( ) ;
2005-11-08 21:39:01 -08:00
preempt_disable ( ) ;
2005-04-16 15:20:36 -07:00
}
}
int powersave_nap ;
# ifdef CONFIG_SYSCTL
/*
* Register the sysctl to set / clear powersave_nap .
*/
static ctl_table powersave_nap_ctl_table [ ] = {
{
. ctl_name = KERN_PPC_POWERSAVE_NAP ,
. procname = " powersave-nap " ,
. data = & powersave_nap ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec ,
} ,
2007-02-14 00:33:46 -08:00
{ }
2005-04-16 15:20:36 -07:00
} ;
static ctl_table powersave_nap_sysctl_root [ ] = {
2007-02-14 00:33:46 -08:00
{
. ctl_name = CTL_KERN ,
. procname = " kernel " ,
2007-10-28 05:34:53 +11:00
. mode = 0555 ,
2007-02-14 00:33:46 -08:00
. child = powersave_nap_ctl_table ,
} ,
{ }
2005-04-16 15:20:36 -07:00
} ;
static int __init
register_powersave_nap_sysctl ( void )
{
2007-02-14 00:34:09 -08:00
register_sysctl_table ( powersave_nap_sysctl_root ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
__initcall ( register_powersave_nap_sysctl ) ;
# endif