5bfb5d690f
Run idle threads with preempt disabled. Also corrected a bugs in arm26's cpu_idle (make it actually call schedule()). How did it ever work before? Might fix the CPU hotplugging hang which Nigel Cunningham noted. We think the bug hits if the idle thread is preempted after checking need_resched() and before going to sleep, then the CPU offlined. After calling stop_machine_run, the CPU eventually returns from preemption and into the idle thread and goes to sleep. The CPU will continue executing previous idle and have no chance to call play_dead. By disabling preemption until we are ready to explicitly schedule, this bug is fixed and the idle threads generally become more robust. From: alexs <ashepard@u.washington.edu> PPC build fix From: Yoichi Yuasa <yuasa@hh.iij4u.or.jp> MIPS build fix Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Yoichi Yuasa <yuasa@hh.iij4u.or.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
113 lines
2.4 KiB
C
113 lines
2.4 KiB
C
/*
|
|
* Idle daemon for PowerPC. Idle daemon will handle any action
|
|
* that needs to be taken when the system becomes idle.
|
|
*
|
|
* Written by Cort Dougan (cort@cs.nmt.edu). Subsequently hacked
|
|
* on by Tom Rini, Armin Kuster, Paul Mackerras and others.
|
|
*
|
|
* 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/config.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/smp_lock.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sysctl.h>
|
|
#include <linux/cpu.h>
|
|
|
|
#include <asm/pgtable.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/system.h>
|
|
#include <asm/io.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/cputable.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/smp.h>
|
|
|
|
void default_idle(void)
|
|
{
|
|
void (*powersave)(void);
|
|
int cpu = smp_processor_id();
|
|
|
|
powersave = ppc_md.power_save;
|
|
|
|
if (!need_resched()) {
|
|
if (powersave != NULL)
|
|
powersave();
|
|
#ifdef CONFIG_SMP
|
|
else {
|
|
set_thread_flag(TIF_POLLING_NRFLAG);
|
|
while (!need_resched() && !cpu_is_offline(cpu))
|
|
barrier();
|
|
clear_thread_flag(TIF_POLLING_NRFLAG);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The body of the idle task.
|
|
*/
|
|
void cpu_idle(void)
|
|
{
|
|
int cpu = smp_processor_id();
|
|
|
|
for (;;) {
|
|
if (ppc_md.idle != NULL)
|
|
ppc_md.idle();
|
|
else
|
|
default_idle();
|
|
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
|
|
cpu_die();
|
|
if (need_resched()) {
|
|
preempt_enable_no_resched();
|
|
schedule();
|
|
preempt_disable();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
|
|
/*
|
|
* Register the sysctl to set/clear powersave_nap.
|
|
*/
|
|
extern int 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,
|
|
},
|
|
{ 0, },
|
|
};
|
|
static ctl_table powersave_nap_sysctl_root[] = {
|
|
{ 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, },
|
|
{ 0,},
|
|
};
|
|
|
|
static int __init
|
|
register_powersave_nap_sysctl(void)
|
|
{
|
|
register_sysctl_table(powersave_nap_sysctl_root, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__initcall(register_powersave_nap_sysctl);
|
|
#endif
|