linux/arch/powerpc/kernel/idle.c
<<
>>
Prefs
   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
  42static int __init powersave_off(char *arg)
  43{
  44        ppc_md.power_save = NULL;
  45        return 0;
  46}
  47__setup("powersave=off", powersave_off);
  48
  49/*
  50 * The body of the idle task.
  51 */
  52void cpu_idle(void)
  53{
  54        if (ppc_md.idle_loop)
  55                ppc_md.idle_loop();     /* doesn't return */
  56
  57        set_thread_flag(TIF_POLLING_NRFLAG);
  58        while (1) {
  59                tick_nohz_stop_sched_tick(1);
  60                while (!need_resched() && !cpu_should_die()) {
  61                        ppc64_runlatch_off();
  62
  63                        if (ppc_md.power_save) {
  64                                clear_thread_flag(TIF_POLLING_NRFLAG);
  65                                /*
  66                                 * smp_mb is so clearing of TIF_POLLING_NRFLAG
  67                                 * is ordered w.r.t. need_resched() test.
  68                                 */
  69                                smp_mb();
  70                                local_irq_disable();
  71
  72                                /* Don't trace irqs off for idle */
  73                                stop_critical_timings();
  74
  75                                /* check again after disabling irqs */
  76                                if (!need_resched() && !cpu_should_die())
  77                                        ppc_md.power_save();
  78
  79                                start_critical_timings();
  80
  81                                local_irq_enable();
  82                                set_thread_flag(TIF_POLLING_NRFLAG);
  83
  84                        } else {
  85                                /*
  86                                 * Go into low thread priority and possibly
  87                                 * low power mode.
  88                                 */
  89                                HMT_low();
  90                                HMT_very_low();
  91                        }
  92                }
  93
  94                HMT_medium();
  95                ppc64_runlatch_on();
  96                tick_nohz_restart_sched_tick();
  97                if (cpu_should_die())
  98                        cpu_die();
  99                preempt_enable_no_resched();
 100                schedule();
 101                preempt_disable();
 102        }
 103}
 104
 105int powersave_nap;
 106
 107#ifdef CONFIG_SYSCTL
 108/*
 109 * Register the sysctl to set/clear powersave_nap.
 110 */
 111static ctl_table powersave_nap_ctl_table[]={
 112        {
 113                .ctl_name       = KERN_PPC_POWERSAVE_NAP,
 114                .procname       = "powersave-nap",
 115                .data           = &powersave_nap,
 116                .maxlen         = sizeof(int),
 117                .mode           = 0644,
 118                .proc_handler   = &proc_dointvec,
 119        },
 120        {}
 121};
 122static ctl_table powersave_nap_sysctl_root[] = {
 123        {
 124                .ctl_name       = CTL_KERN,
 125                .procname       = "kernel",
 126                .mode           = 0555,
 127                .child          = powersave_nap_ctl_table,
 128        },
 129        {}
 130};
 131
 132static int __init
 133register_powersave_nap_sysctl(void)
 134{
 135        register_sysctl_table(powersave_nap_sysctl_root);
 136
 137        return 0;
 138}
 139__initcall(register_powersave_nap_sysctl);
 140#endif
 141