diff options
101 files changed, 454 insertions, 1327 deletions
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 1f8c72959fb..52cd2a4a3ff 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -95,8 +95,6 @@ register struct thread_info *__current_thread_info __asm__("$8");  #define TS_POLLING		0x0010	/* idle task polling need_resched,  					   skip sending interrupt */ -#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) -  #ifndef __ASSEMBLY__  #define HAVE_SET_RESTORE_SIGMASK	1  static inline void set_restore_sigmask(void) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 63d27fb9b02..a3fd8a29cca 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -46,25 +46,6 @@  void (*pm_power_off)(void) = machine_power_off;  EXPORT_SYMBOL(pm_power_off); -void -cpu_idle(void) -{ -	current_thread_info()->status |= TS_POLLING; - -	while (1) { -		/* FIXME -- EV6 and LCA45 know how to power down -		   the CPU.  */ - -		rcu_idle_enter(); -		while (!need_resched()) -			cpu_relax(); - -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} -} - -  struct halt_info {  	int mode;  	char *restart_cmd; diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 9603bc234b4..7b60834fb4b 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -167,8 +167,7 @@ smp_callin(void)  	      cpuid, current, current->active_mm));  	preempt_disable(); -	/* Do nothing.  */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */ diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 0a7531d9929..cad66851e0c 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -41,37 +41,12 @@ SYSCALL_DEFINE0(arc_gettls)  	return task_thread_info(current)->thr_ptr;  } -static inline void arch_idle(void) +void arch_cpu_idle(void)  {  	/* sleep, but enable all interrupts before committing */  	__asm__("sleep 0x3");  } -void cpu_idle(void) -{ -	/* Since we SLEEP in idle loop, TIF_POLLING_NRFLAG can't be set */ - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -doze: -		local_irq_disable(); -		if (!need_resched()) { -			arch_idle(); -			goto doze; -		} else { -			local_irq_enable(); -		} - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); - -		schedule_preempt_disabled(); -	} -} -  asmlinkage void ret_from_fork(void);  /* Layout of Child kernel mode stack as setup at the end of this function is diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 3af3e06dcf0..5c7fd603d21 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -141,7 +141,7 @@ void __cpuinit start_kernel_secondary(void)  	local_irq_enable();  	preempt_disable(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bbddefea77b..a39e3214ea3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -15,6 +15,7 @@ config ARM  	select GENERIC_IRQ_SHOW  	select GENERIC_PCI_IOMAP  	select GENERIC_SMP_IDLE_THREAD +	select GENERIC_IDLE_POLL_SETUP  	select GENERIC_STRNCPY_FROM_USER  	select GENERIC_STRNLEN_USER  	select HARDIRQS_SW_RESEND diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h index 5a85f148b60..21a23e378bb 100644 --- a/arch/arm/include/asm/system_misc.h +++ b/arch/arm/include/asm/system_misc.h @@ -21,9 +21,6 @@ extern void (*arm_pm_idle)(void);  extern unsigned int user_debug; -extern void disable_hlt(void); -extern void enable_hlt(void); -  #endif /* !__ASSEMBLY__ */  #endif /* __ASM_ARM_SYSTEM_MISC_H */ diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 047d3e40e47..c9a5e2ce8aa 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -57,38 +57,6 @@ static const char *isa_modes[] = {    "ARM" , "Thumb" , "Jazelle", "ThumbEE"  }; -static volatile int hlt_counter; - -void disable_hlt(void) -{ -	hlt_counter++; -} - -EXPORT_SYMBOL(disable_hlt); - -void enable_hlt(void) -{ -	hlt_counter--; -	BUG_ON(hlt_counter < 0); -} - -EXPORT_SYMBOL(enable_hlt); - -static int __init nohlt_setup(char *__unused) -{ -	hlt_counter = 1; -	return 1; -} - -static int __init hlt_setup(char *__unused) -{ -	hlt_counter = 0; -	return 1; -} - -__setup("nohlt", nohlt_setup); -__setup("hlt", hlt_setup); -  extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);  typedef void (*phys_reset_t)(unsigned long); @@ -172,54 +140,38 @@ static void default_idle(void)  	local_irq_enable();  } -/* - * The idle thread. - * We always respect 'hlt_counter' to prevent low power idle. - */ -void cpu_idle(void) +void arch_cpu_idle_prepare(void)  {  	local_fiq_enable(); +} -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		ledtrig_cpu(CPU_LED_IDLE_START); -		while (!need_resched()) { -#ifdef CONFIG_HOTPLUG_CPU -			if (cpu_is_offline(smp_processor_id())) -				cpu_die(); +void arch_cpu_idle_enter(void) +{ +	ledtrig_cpu(CPU_LED_IDLE_START); +#ifdef CONFIG_PL310_ERRATA_769419 +	wmb();  #endif +} -			/* -			 * We need to disable interrupts here -			 * to ensure we don't miss a wakeup call. -			 */ -			local_irq_disable(); -#ifdef CONFIG_PL310_ERRATA_769419 -			wmb(); +void arch_cpu_idle_exit(void) +{ +	ledtrig_cpu(CPU_LED_IDLE_END); +} + +#ifdef CONFIG_HOTPLUG_CPU +void arch_cpu_idle_dead(void) +{ +	cpu_die(); +}  #endif -			if (hlt_counter) { -				local_irq_enable(); -				cpu_relax(); -			} else if (!need_resched()) { -				stop_critical_timings(); -				if (cpuidle_idle_call()) -					default_idle(); -				start_critical_timings(); -				/* -				 * default_idle functions must always -				 * return with IRQs enabled. -				 */ -				WARN_ON(irqs_disabled()); -			} else -				local_irq_enable(); -		} -		ledtrig_cpu(CPU_LED_IDLE_END); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} + +/* + * Called from the core idle loop. + */ +void arch_cpu_idle(void) +{ +	if (cpuidle_idle_call()) +		default_idle();  }  static char reboot_mode = 'h'; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 1f2ccccaf00..4619177bcfe 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -336,7 +336,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)  	/*  	 * OK, it's off to the idle thread for us  	 */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  void __init smp_cpus_done(unsigned int max_cpus) diff --git a/arch/arm/mach-gemini/idle.c b/arch/arm/mach-gemini/idle.c index 92bbd6bb600..87dff4f5059 100644 --- a/arch/arm/mach-gemini/idle.c +++ b/arch/arm/mach-gemini/idle.c @@ -13,9 +13,11 @@ static void gemini_idle(void)  	 * will never wakeup... Acctualy it is not very good to enable  	 * interrupts first since scheduler can miss a tick, but there is  	 * no other way around this. Platforms that needs it for power saving -	 * should call enable_hlt() in init code, since by default it is +	 * should enable it in init code, since by default it is  	 * disabled.  	 */ + +	/* FIXME: Enabling interrupts here is racy! */  	local_irq_enable();  	cpu_do_idle();  } diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c index 020852d3bdd..6d8f6d1669f 100644 --- a/arch/arm/mach-gemini/irq.c +++ b/arch/arm/mach-gemini/irq.c @@ -15,6 +15,8 @@  #include <linux/stddef.h>  #include <linux/list.h>  #include <linux/sched.h> +#include <linux/cpu.h> +  #include <asm/irq.h>  #include <asm/mach/irq.h>  #include <asm/system_misc.h> @@ -77,7 +79,7 @@ void __init gemini_init_irq(void)  	 * Disable the idle handler by default since it is buggy  	 * For more info see arch/arm/mach-gemini/idle.c  	 */ -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  	request_resource(&iomem_resource, &irq_resource); diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 1dbeb7c99d5..6600cff6bd9 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -29,6 +29,7 @@  #include <linux/io.h>  #include <linux/export.h>  #include <linux/gpio.h> +#include <linux/cpu.h>  #include <mach/udc.h>  #include <mach/hardware.h> @@ -239,7 +240,7 @@ void __init ixp4xx_init_irq(void)  	 * ixp4xx does not implement the XScale PWRMODE register  	 * so it must not call cpu_do_idle().  	 */ -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  	/* Route all sources to IRQ instead of FIQ */  	*IXP4XX_ICLR = 0x0; diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index 7a7690ab6cb..db37f49da5a 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -43,6 +43,7 @@  #include <linux/module.h>  #include <linux/io.h>  #include <linux/atomic.h> +#include <linux/cpu.h>  #include <asm/fncpy.h>  #include <asm/system_misc.h> @@ -584,8 +585,7 @@ static void omap_pm_init_proc(void)  static int omap_pm_prepare(void)  {  	/* We cannot sleep in idle until we have resumed */ -	disable_hlt(); - +	cpu_idle_poll_ctrl(true);  	return 0;  } @@ -621,7 +621,7 @@ static int omap_pm_enter(suspend_state_t state)  static void omap_pm_finish(void)  { -	enable_hlt(); +	cpu_idle_poll_ctrl(false);  } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index a202a478510..e512253601c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -138,6 +138,7 @@  #include <linux/spinlock.h>  #include <linux/slab.h>  #include <linux/bootmem.h> +#include <linux/cpu.h>  #include <asm/system_misc.h> @@ -2157,7 +2158,7 @@ static int _enable(struct omap_hwmod *oh)  	if (soc_ops.enable_module)  		soc_ops.enable_module(oh);  	if (oh->flags & HWMOD_BLOCK_WFI) -		disable_hlt(); +		cpu_idle_poll_ctrl(true);  	if (soc_ops.update_context_lost)  		soc_ops.update_context_lost(oh); @@ -2221,7 +2222,7 @@ static int _idle(struct omap_hwmod *oh)  	_del_initiator_dep(oh, mpu_oh);  	if (oh->flags & HWMOD_BLOCK_WFI) -		enable_hlt(); +		cpu_idle_poll_ctrl(false);  	if (soc_ops.disable_module)  		soc_ops.disable_module(oh); @@ -2331,7 +2332,7 @@ static int _shutdown(struct omap_hwmod *oh)  		_del_initiator_dep(oh, mpu_oh);  		/* XXX what about the other system initiators here? dma, dsp */  		if (oh->flags & HWMOD_BLOCK_WFI) -			enable_hlt(); +			cpu_idle_poll_ctrl(false);  		if (soc_ops.disable_module)  			soc_ops.disable_module(oh);  		_disable_clocks(oh); diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 673a4c1d1d7..dec553349ae 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -218,7 +218,7 @@ static int omap_pm_enter(suspend_state_t suspend_state)  static int omap_pm_begin(suspend_state_t state)  { -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  	if (cpu_is_omap34xx())  		omap_prcm_irq_prepare();  	return 0; @@ -226,8 +226,7 @@ static int omap_pm_begin(suspend_state_t state)  static void omap_pm_end(void)  { -	enable_hlt(); -	return; +	cpu_idle_poll_ctrl(false);  }  static void omap_pm_finish(void) diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index 35a8014529c..94fbb815680 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -14,6 +14,7 @@  #include <linux/init.h>  #include <linux/of.h>  #include <linux/of_platform.h> +#include <linux/cpu.h>  #include <asm/system_misc.h>  #include <asm/mach/arch.h>  #include <mach/orion5x.h> @@ -52,7 +53,7 @@ static void __init orion5x_dt_init(void)  	 */  	if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {  		printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n"); -		disable_hlt(); +		cpu_idle_poll_ctrl(true);  	}  	if (of_machine_is_compatible("lacie,ethernet-disk-mini-v2")) diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index d068f1431c4..ad71c8a03ff 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -293,7 +293,7 @@ void __init orion5x_init(void)  	 */  	if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {  		printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n"); -		disable_hlt(); +		cpu_idle_poll_ctrl(true);  	}  	/* diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index b63dec84819..15355572498 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -10,6 +10,7 @@  #include <linux/sched.h>  #include <linux/serial_8250.h>  #include <linux/io.h> +#include <linux/cpu.h>  #include <asm/setup.h>  #include <asm/mach-types.h> @@ -130,7 +131,7 @@ static void __init shark_timer_init(void)  static void shark_init_early(void)  { -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  }  MACHINE_START(SHARK, "Shark") diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c index 47d83f7a70b..5d92b5dd486 100644 --- a/arch/arm/mach-shmobile/suspend.c +++ b/arch/arm/mach-shmobile/suspend.c @@ -12,6 +12,8 @@  #include <linux/suspend.h>  #include <linux/module.h>  #include <linux/err.h> +#include <linux/cpu.h> +  #include <asm/io.h>  #include <asm/system_misc.h> @@ -23,13 +25,13 @@ static int shmobile_suspend_default_enter(suspend_state_t suspend_state)  static int shmobile_suspend_begin(suspend_state_t state)  { -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  	return 0;  }  static void shmobile_suspend_end(void)  { -	enable_hlt(); +	cpu_idle_poll_ctrl(false);  }  struct platform_suspend_ops shmobile_suspend_ops = { diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c index 7abdb9645c5..e65a80a1ac7 100644 --- a/arch/arm/mach-w90x900/dev.c +++ b/arch/arm/mach-w90x900/dev.c @@ -19,6 +19,7 @@  #include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/slab.h> +#include <linux/cpu.h>  #include <linux/mtd/physmap.h>  #include <linux/mtd/mtd.h> @@ -531,7 +532,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = {  void __init nuc900_board_init(struct platform_device **device, int size)  { -	disable_hlt(); +	cpu_idle_poll_ctrl(true);  	platform_add_devices(device, size);  	platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev));  	spi_register_board_info(nuc900_spi_board_info, diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 0337cdb0667..83a0ad5936a 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -84,11 +84,15 @@ EXPORT_SYMBOL_GPL(pm_power_off);  void (*pm_restart)(const char *cmd);  EXPORT_SYMBOL_GPL(pm_restart); +void arch_cpu_idle_prepare(void) +{ +	local_fiq_enable(); +}  /*   * This is our default idle handler.   */ -static void default_idle(void) +void arch_cpu_idle(void)  {  	/*  	 * This should do all the clock switching and wait for interrupt @@ -98,43 +102,6 @@ static void default_idle(void)  	local_irq_enable();  } -/* - * The idle thread. - * We always respect 'hlt_counter' to prevent low power idle. - */ -void cpu_idle(void) -{ -	local_fiq_enable(); - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) { -			/* -			 * We need to disable interrupts here to ensure -			 * we don't miss a wakeup call. -			 */ -			local_irq_disable(); -			if (!need_resched()) { -				stop_critical_timings(); -				default_idle(); -				start_critical_timings(); -				/* -				 * default_idle functions should always return -				 * with IRQs enabled. -				 */ -				WARN_ON(irqs_disabled()); -			} else { -				local_irq_enable(); -			} -		} -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} -} -  void machine_shutdown(void)  {  #ifdef CONFIG_SMP diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index bdd34597254..261445c4666 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -216,7 +216,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)  	/*  	 * OK, it's off to the idle thread for us  	 */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  void __init smp_cpus_done(unsigned int max_cpus) diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index fd78f58ea79..073c3c2fa52 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -30,18 +30,9 @@ EXPORT_SYMBOL(pm_power_off);   * This file handles the architecture-dependent parts of process handling..   */ -void cpu_idle(void) +void arch_cpu_idle(void)  { -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) -			cpu_idle_sleep(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} +	cpu_enter_idle();  }  void machine_halt(void) diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index 05ad29112ff..869a1c6ffee 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -12,6 +12,7 @@  #include <linux/irq.h>  #include <linux/kernel.h>  #include <linux/time.h> +#include <linux/cpu.h>  #include <asm/sysreg.h> @@ -87,13 +88,17 @@ static void comparator_mode(enum clock_event_mode mode,  		pr_debug("%s: start\n", evdev->name);  		/* FALLTHROUGH */  	case CLOCK_EVT_MODE_RESUME: -		cpu_disable_idle_sleep(); +		/* +		 * If we're using the COUNT and COMPARE registers we +		 * need to force idle poll. +		 */ +		cpu_idle_poll_ctrl(true);  		break;  	case CLOCK_EVT_MODE_UNUSED:  	case CLOCK_EVT_MODE_SHUTDOWN:  		sysreg_write(COMPARE, 0);  		pr_debug("%s: stop\n", evdev->name); -		cpu_enable_idle_sleep(); +		cpu_idle_poll_ctrl(false);  		break;  	default:  		BUG(); diff --git a/arch/avr32/mach-at32ap/include/mach/pm.h b/arch/avr32/mach-at32ap/include/mach/pm.h index 979b355b77b..f29ff2cd23d 100644 --- a/arch/avr32/mach-at32ap/include/mach/pm.h +++ b/arch/avr32/mach-at32ap/include/mach/pm.h @@ -21,30 +21,6 @@  extern void cpu_enter_idle(void);  extern void cpu_enter_standby(unsigned long sdramc_base); -extern bool disable_idle_sleep; - -static inline void cpu_disable_idle_sleep(void) -{ -	disable_idle_sleep = true; -} - -static inline void cpu_enable_idle_sleep(void) -{ -	disable_idle_sleep = false; -} - -static inline void cpu_idle_sleep(void) -{ -	/* -	 * If we're using the COUNT and COMPARE registers for -	 * timekeeping, we can't use the IDLE state. -	 */ -	if (disable_idle_sleep) -		cpu_relax(); -	else -		cpu_enter_idle(); -} -  void intc_set_suspend_handler(unsigned long offset);  #endif diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S index f868f4ce761..1c8e4e6bff0 100644 --- a/arch/avr32/mach-at32ap/pm-at32ap700x.S +++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S @@ -18,13 +18,6 @@  /* Same as 0xfff00000 but fits in a 21 bit signed immediate */  #define PM_BASE	-0x100000 -	.section .bss, "wa", @nobits -	.global	disable_idle_sleep -	.type	disable_idle_sleep, @object -disable_idle_sleep: -	.int	4 -	.size	disable_idle_sleep, . - disable_idle_sleep -  	/* Keep this close to the irq handlers */  	.section .irq.text, "ax", @progbits diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 9782c0329c1..4aa5545c4fd 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -46,15 +46,14 @@ EXPORT_SYMBOL(pm_power_off);   * The idle loop on BFIN   */  #ifdef CONFIG_IDLE_L1 -static void default_idle(void)__attribute__((l1_text)); -void cpu_idle(void)__attribute__((l1_text)); +void arch_cpu_idle(void)__attribute__((l1_text));  #endif  /*   * This is our default idle handler.  We need to disable   * interrupts here to ensure we don't miss a wakeup call.   */ -static void default_idle(void) +void arch_cpu_idle(void)  {  #ifdef CONFIG_IPIPE  	ipipe_suspend_domain(); @@ -66,31 +65,12 @@ static void default_idle(void)  	hard_local_irq_enable();  } -/* - * The idle thread.  We try to conserve power, while trying to keep - * overall latency low.  The architecture specific idle is passed - * a value to indicate the level of "idleness" of the system. - */ -void cpu_idle(void) -{ -	/* endless idle loop with no priority at all */ -	while (1) { -  #ifdef CONFIG_HOTPLUG_CPU -		if (cpu_is_offline(smp_processor_id())) -			cpu_die(); -#endif -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) -			default_idle(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} +void arch_cpu_idle_dead(void) +{ +	cpu_die();  } +#endif  /*   * Do necessary setup to start up a newly executed thread. diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index bb61ae4986e..1bc2ce6f3c9 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -335,7 +335,7 @@ void __cpuinit secondary_start_kernel(void)  	 */  	calibrate_delay(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  void __init smp_prepare_boot_cpu(void) diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c index 6434df476f7..57d2ea8d197 100644 --- a/arch/c6x/kernel/process.c +++ b/arch/c6x/kernel/process.c @@ -33,7 +33,7 @@ extern asmlinkage void ret_from_kernel_thread(void);  void (*pm_power_off)(void);  EXPORT_SYMBOL(pm_power_off); -static void c6x_idle(void) +void arch_cpu_idle(void)  {  	unsigned long tmp; @@ -49,32 +49,6 @@ static void c6x_idle(void)  		      : "=b"(tmp));  } -/* - * The idle loop for C64x - */ -void cpu_idle(void) -{ -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (1) { -			local_irq_disable(); -			if (need_resched()) { -				local_irq_enable(); -				break; -			} -			c6x_idle(); /* enables local irqs */ -		} -		rcu_idle_exit(); -		tick_nohz_idle_exit(); - -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} -} -  static void halt_loop(void)  {  	printk(KERN_EMERG "System Halted, OK to turn off power\n"); diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index b1018750cff..2ba23c13df6 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -30,8 +30,9 @@ void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */  void default_idle(void)  {  #ifdef CONFIG_ETRAX_GPIO -  etrax_gpio_wake_up_check(); +	etrax_gpio_wake_up_check();  #endif +	local_irq_enable();  }  /* diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 2b23ef0e445..57451faa9b2 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -20,18 +20,12 @@  extern void stop_watchdog(void); -extern int cris_hlt_counter; -  /* We use this if we don't have any better idle routine. */  void default_idle(void)  { -	local_irq_disable(); -	if (!need_resched() && !cris_hlt_counter) { -	        /* Halt until exception. */ -		__asm__ volatile("ei    \n\t" -                                 "halt      "); -	} -	local_irq_enable(); +	/* Halt until exception. */ +	__asm__ volatile("ei    \n\t" +			 "halt      ");  }  /* diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 04a16edd540..cdd12028de0 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -145,8 +145,6 @@ smp_boot_one_cpu(int cpuid, struct task_struct idle)   * specific stuff such as the local timer and the MMU. */  void __init smp_callin(void)  { -	extern void cpu_idle(void); -  	int cpu = cpu_now_booting;  	reg_intr_vect_rw_mask vect_mask = {0}; @@ -170,7 +168,7 @@ void __init smp_callin(void)  	local_irq_enable();  	set_cpu_online(cpu, true); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* Stop execution on this CPU.*/ diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h index 675823f70c0..c0a29b96b92 100644 --- a/arch/cris/include/asm/processor.h +++ b/arch/cris/include/asm/processor.h @@ -65,13 +65,6 @@ static inline void release_thread(struct task_struct *dead_task)  #define cpu_relax()     barrier() -/* - * disable hlt during certain critical i/o operations - */ -#define HAVE_DISABLE_HLT -void disable_hlt(void); -void enable_hlt(void); -  void default_idle(void);  #endif /* __ASM_CRIS_PROCESSOR_H */ diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index 104ff4dd9b9..b78498eb079 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -29,59 +29,14 @@  //#define DEBUG -/* - * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if - * there would ever be a halt sequence (for power save when idle) with - * some largish delay when halting or resuming *and* a driver that can't - * afford that delay.  The hlt_counter would then be checked before - * executing the halt sequence, and the driver marks the unhaltable - * region by enable_hlt/disable_hlt. - */ - -int cris_hlt_counter=0; - -void disable_hlt(void) -{ -	cris_hlt_counter++; -} - -EXPORT_SYMBOL(disable_hlt); - -void enable_hlt(void) -{ -	cris_hlt_counter--; -} - -EXPORT_SYMBOL(enable_hlt); -   extern void default_idle(void);  void (*pm_power_off)(void);  EXPORT_SYMBOL(pm_power_off); -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ - -void cpu_idle (void) +void arch_cpu_idle(void)  { -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) { -			/* -			 * Mark this as an RCU critical section so that -			 * synchronize_kernel() in the unload path waits -			 * for our completion. -			 */ -			default_idle(); -		} -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} +	default_idle();  }  void hard_reset_now (void); diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 23916b2a12a..5d40aeb7712 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -59,29 +59,12 @@ static void core_sleep_idle(void)  	mb();  } -void (*idle)(void) = core_sleep_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) +void arch_cpu_idle(void)  { -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) { -			check_pgt_cache(); - -			if (!frv_dma_inprogress && idle) -				idle(); -		} -		rcu_idle_exit(); - -		schedule_preempt_disabled(); -	} +	if (!frv_dma_inprogress) +		core_sleep_idle(); +	else +		local_irq_enable();  }  void machine_restart(char * __unused) diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index b609f63f159..a17d2cd463d 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -53,40 +53,13 @@ asmlinkage void ret_from_kernel_thread(void);   * The idle loop on an H8/300..   */  #if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM) -static void default_idle(void) +void arch_cpu_idle(void)  { -	local_irq_disable(); -	if (!need_resched()) { -		local_irq_enable(); -		/* XXX: race here! What if need_resched() gets set now? */ -		__asm__("sleep"); -	} else -		local_irq_enable(); -} -#else -static void default_idle(void) -{ -	cpu_relax(); +	local_irq_enable(); +	/* XXX: race here! What if need_resched() gets set now? */ +	__asm__("sleep");  }  #endif -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			idle(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} -}  void machine_restart(char * __unused)  { diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index 06ae9ffcabd..9b948c619a0 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -51,28 +51,11 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)   *  If hardware or VM offer wait termination even though interrupts   *  are disabled.   */ -static void default_idle(void) +void arch_cpu_idle(void)  {  	__vmwait(); -} - -void (*idle_sleep)(void) = default_idle; - -void cpu_idle(void) -{ -	while (1) { -		tick_nohz_idle_enter(); -		local_irq_disable(); -		while (!need_resched()) { -			idle_sleep(); -			/*  interrupts wake us up, but aren't serviced  */ -			local_irq_enable();	/* service interrupt   */ -			local_irq_disable(); -		} -		local_irq_enable(); -		tick_nohz_idle_exit(); -		schedule(); -	} +	/*  interrupts wake us up, but irqs are still disabled */ +	local_irq_enable();  }  /* diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c index 8e095dffd07..0e364ca4319 100644 --- a/arch/hexagon/kernel/smp.c +++ b/arch/hexagon/kernel/smp.c @@ -184,7 +184,7 @@ void __cpuinit start_secondary(void)  	local_irq_enable(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  } diff --git a/arch/ia64/include/asm/irqflags.h b/arch/ia64/include/asm/irqflags.h index 2b68d856dc7..1bf2cf2f4ab 100644 --- a/arch/ia64/include/asm/irqflags.h +++ b/arch/ia64/include/asm/irqflags.h @@ -89,6 +89,7 @@ static inline bool arch_irqs_disabled(void)  static inline void arch_safe_halt(void)  { +	arch_local_irq_enable();  	ia64_pal_halt_light();	/* PAL_HALT_LIGHT */  } diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h index 020d655ed08..cade13dd029 100644 --- a/arch/ia64/include/asm/thread_info.h +++ b/arch/ia64/include/asm/thread_info.h @@ -131,8 +131,6 @@ struct thread_info {  #define TS_POLLING		1 	/* true if in idle loop and not sleeping */  #define TS_RESTORE_SIGMASK	2	/* restore signal mask in do_signal() */ -#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) -  #ifndef __ASSEMBLY__  #define HAVE_SET_RESTORE_SIGMASK	1  static inline void set_restore_sigmask(void) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 2eda28414ab..9ea25fce06d 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -42,6 +42,7 @@  #include <linux/completion.h>  #include <linux/tracehook.h>  #include <linux/slab.h> +#include <linux/cpu.h>  #include <asm/errno.h>  #include <asm/intrinsics.h> @@ -1322,8 +1323,6 @@ out:  }  EXPORT_SYMBOL(pfm_unregister_buffer_fmt); -extern void update_pal_halt_status(int); -  static int  pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)  { @@ -1371,9 +1370,9 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)  		cpu));  	/* -	 * disable default_idle() to go to PAL_HALT +	 * Force idle() into poll mode  	 */ -	update_pal_halt_status(0); +	cpu_idle_poll_ctrl(true);  	UNLOCK_PFS(flags); @@ -1430,11 +1429,8 @@ pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu)  		is_syswide,  		cpu)); -	/* -	 * if possible, enable default_idle() to go into PAL_HALT -	 */ -	if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0) -		update_pal_halt_status(1); +	/* Undo forced polling. Last session reenables pal_halt */ +	cpu_idle_poll_ctrl(false);  	UNLOCK_PFS(flags); diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 6f7dc8b7b35..a26fc640e4c 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -209,41 +209,13 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)  	local_irq_disable();	/* force interrupt disable */  } -static int pal_halt        = 1; -static int can_do_pal_halt = 1; -  static int __init nohalt_setup(char * str)  { -	pal_halt = can_do_pal_halt = 0; +	cpu_idle_poll_ctrl(true);  	return 1;  }  __setup("nohalt", nohalt_setup); -void -update_pal_halt_status(int status) -{ -	can_do_pal_halt = pal_halt && status; -} - -/* - * We use this if we don't have any better idle routine.. - */ -void -default_idle (void) -{ -	local_irq_enable(); -	while (!need_resched()) { -		if (can_do_pal_halt) { -			local_irq_disable(); -			if (!need_resched()) { -				safe_halt(); -			} -			local_irq_enable(); -		} else -			cpu_relax(); -	} -} -  #ifdef CONFIG_HOTPLUG_CPU  /* We don't actually take CPU down, just spin without interrupts. */  static inline void play_dead(void) @@ -270,47 +242,29 @@ static inline void play_dead(void)  }  #endif /* CONFIG_HOTPLUG_CPU */ -void __attribute__((noreturn)) -cpu_idle (void) +void arch_cpu_idle_dead(void)  { -	void (*mark_idle)(int) = ia64_mark_idle; -  	int cpu = smp_processor_id(); +	play_dead(); +} -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		if (can_do_pal_halt) { -			current_thread_info()->status &= ~TS_POLLING; -			/* -			 * TS_POLLING-cleared state must be visible before we -			 * test NEED_RESCHED: -			 */ -			smp_mb(); -		} else { -			current_thread_info()->status |= TS_POLLING; -		} +void arch_cpu_idle(void) +{ +	void (*mark_idle)(int) = ia64_mark_idle; -		if (!need_resched()) {  #ifdef CONFIG_SMP -			min_xtp(); +	min_xtp();  #endif -			rmb(); -			if (mark_idle) -				(*mark_idle)(1); +	rmb(); +	if (mark_idle) +		(*mark_idle)(1); + +	safe_halt(); -			default_idle(); -			if (mark_idle) -				(*mark_idle)(0); +	if (mark_idle) +		(*mark_idle)(0);  #ifdef CONFIG_SMP -			normal_xtp(); +	normal_xtp();  #endif -		} -		rcu_idle_exit(); -		schedule_preempt_disabled(); -		check_pgt_cache(); -		if (cpu_is_offline(cpu)) -			play_dead(); -	}  }  void diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 500f1e4d9f9..8d87168d218 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -455,7 +455,7 @@ start_secondary (void *unused)  	preempt_disable();  	smp_callin(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  	return 0;  } diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index bde899e155d..e2d049018c3 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -47,24 +47,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  void (*pm_power_off)(void) = NULL;  EXPORT_SYMBOL(pm_power_off); -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle (void) -{ -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			cpu_relax(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} -} -  void machine_restart(char *__unused)  {  #if defined(CONFIG_PLAT_MAPPI3) diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c index 13168a769f8..0ac558adc60 100644 --- a/arch/m32r/kernel/smpboot.c +++ b/arch/m32r/kernel/smpboot.c @@ -432,7 +432,7 @@ int __init start_secondary(void *unused)  	 */  	local_flush_tlb_all(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  	return 0;  } diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index d538694ad20..c55ff719fa7 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -51,40 +51,16 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  		return sw->retpc;  } -/* - * The idle loop on an m68k.. - */ -static void default_idle(void) +void arch_cpu_idle(void)  { -	if (!need_resched())  #if defined(MACH_ATARI_ONLY) -		/* block out HSYNC on the atari (falcon) */ -		__asm__("stop #0x2200" : : : "cc"); +	/* block out HSYNC on the atari (falcon) */ +	__asm__("stop #0x2200" : : : "cc");  #else -		__asm__("stop #0x2000" : : : "cc"); +	__asm__("stop #0x2000" : : : "cc");  #endif  } -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			idle(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} -} -  void machine_restart(char * __unused)  {  	if (mach_reset) diff --git a/arch/metag/include/asm/thread_info.h b/arch/metag/include/asm/thread_info.h index 0ecd34d8b5f..7c4a3300614 100644 --- a/arch/metag/include/asm/thread_info.h +++ b/arch/metag/include/asm/thread_info.h @@ -150,6 +150,4 @@ static inline int kstack_end(void *addr)  #define _TIF_WORK_MASK		(_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \  				 _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP)) -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c index c6efe62e5b7..dc592354456 100644 --- a/arch/metag/kernel/process.c +++ b/arch/metag/kernel/process.c @@ -22,6 +22,7 @@  #include <linux/pm.h>  #include <linux/syscalls.h>  #include <linux/uaccess.h> +#include <linux/smp.h>  #include <asm/core_reg.h>  #include <asm/user_gateway.h>  #include <asm/tcm.h> @@ -31,7 +32,7 @@  /*   * Wait for the next interrupt and enable local interrupts   */ -static inline void arch_idle(void) +void arch_cpu_idle(void)  {  	int tmp; @@ -59,36 +60,12 @@ static inline void arch_idle(void)  		      : "r" (get_trigger_mask()));  } -void cpu_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched()) { -			/* -			 * We need to disable interrupts here to ensure we don't -			 * miss a wakeup call. -			 */ -			local_irq_disable(); -			if (!need_resched()) {  #ifdef CONFIG_HOTPLUG_CPU -				if (cpu_is_offline(smp_processor_id())) -					cpu_die(); -#endif -				arch_idle(); -			} else { -				local_irq_enable(); -			} -		} - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	 } +void arch_cpu_idle_dead(void) +{ +	cpu_die();  } +#endif  void (*pm_power_off)(void);  EXPORT_SYMBOL(pm_power_off); diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c index 4b6d1f14df3..4de8fc8e31a 100644 --- a/arch/metag/kernel/smp.c +++ b/arch/metag/kernel/smp.c @@ -297,7 +297,7 @@ asmlinkage void secondary_start_kernel(void)  	/*  	 * OK, it's off to the idle thread for us  	 */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  void __init smp_cpus_done(unsigned int max_cpus) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 1323fa2530e..a827057c792 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -26,6 +26,7 @@ config MICROBLAZE  	select GENERIC_CPU_DEVICES  	select GENERIC_ATOMIC64  	select GENERIC_CLOCKEVENTS +	select GENERIC_IDLE_POLL_SETUP  	select MODULES_USE_ELF_RELA  	select CLONE_BACKWARDS diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index 0759153e811..d6e0ffea28b 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -22,7 +22,6 @@  extern const struct seq_operations cpuinfo_op;  # define cpu_relax()		barrier() -# define cpu_sleep()		do {} while (0)  #define task_pt_regs(tsk) \  		(((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1) @@ -160,10 +159,6 @@ unsigned long get_wchan(struct task_struct *p);  #  define STACK_TOP	TASK_SIZE  #  define STACK_TOP_MAX	STACK_TOP -void disable_hlt(void); -void enable_hlt(void); -void default_idle(void); -  #ifdef CONFIG_DEBUG_FS  extern struct dentry *of_debugfs_root;  #endif diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h index 008f30433d2..de26ea6373d 100644 --- a/arch/microblaze/include/asm/thread_info.h +++ b/arch/microblaze/include/asm/thread_info.h @@ -182,7 +182,6 @@ static inline bool test_and_clear_restore_sigmask(void)  	ti->status &= ~TS_RESTORE_SIGMASK;  	return true;  } -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)  #endif  #endif /* __KERNEL__ */ diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index fa0ea609137..7cce2e9c171 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -44,71 +44,6 @@ void show_regs(struct pt_regs *regs)  void (*pm_power_off)(void) = NULL;  EXPORT_SYMBOL(pm_power_off); -static int hlt_counter = 1; - -void disable_hlt(void) -{ -	hlt_counter++; -} -EXPORT_SYMBOL(disable_hlt); - -void enable_hlt(void) -{ -	hlt_counter--; -} -EXPORT_SYMBOL(enable_hlt); - -static int __init nohlt_setup(char *__unused) -{ -	hlt_counter = 1; -	return 1; -} -__setup("nohlt", nohlt_setup); - -static int __init hlt_setup(char *__unused) -{ -	hlt_counter = 0; -	return 1; -} -__setup("hlt", hlt_setup); - -void default_idle(void) -{ -	if (likely(hlt_counter)) { -		local_irq_disable(); -		stop_critical_timings(); -		cpu_relax(); -		start_critical_timings(); -		local_irq_enable(); -	} else { -		clear_thread_flag(TIF_POLLING_NRFLAG); -		smp_mb__after_clear_bit(); -		local_irq_disable(); -		while (!need_resched()) -			cpu_sleep(); -		local_irq_enable(); -		set_thread_flag(TIF_POLLING_NRFLAG); -	} -} - -void cpu_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) -			default_idle(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); - -		schedule_preempt_disabled(); -		check_pgt_cache(); -	} -} -  void flush_thread(void)  {  } diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 3be4405c2d1..cfc742d75b7 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -41,44 +41,26 @@  #include <asm/inst.h>  #include <asm/stacktrace.h> -/* - * The idle thread. There's no useful work to be done, so just try to conserve - * power and have a low exit latency (ie sit in a loop waiting for somebody to - * say that they'd like to reschedule) - */ -void __noreturn cpu_idle(void) +#ifdef CONFIG_HOTPLUG_CPU +void arch_cpu_idle_dead(void)  { -	int cpu; - -	/* CPU is going idle. */ -	cpu = smp_processor_id(); +	/* What the heck is this check doing ? */ +	if (!cpu_isset(smp_processor_id(), cpu_callin_map)) +		play_dead(); +} +#endif -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched() && cpu_online(cpu)) { +void arch_cpu_idle(void) +{  #ifdef CONFIG_MIPS_MT_SMTC -			extern void smtc_idle_loop_hook(void); +	extern void smtc_idle_loop_hook(void); -			smtc_idle_loop_hook(); +	smtc_idle_loop_hook();  #endif - -			if (cpu_wait) { -				/* Don't trace irqs off for idle */ -				stop_critical_timings(); -				(*cpu_wait)(); -				start_critical_timings(); -			} -		} -#ifdef CONFIG_HOTPLUG_CPU -		if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map)) -			play_dead(); -#endif -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} +	if (cpu_wait) +		(*cpu_wait)(); +	else +		local_irq_enable();  }  asmlinkage void ret_from_fork(void); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 66bf4e22d9b..aee04af213c 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -139,7 +139,7 @@ asmlinkage __cpuinit void start_secondary(void)  	WARN_ON_ONCE(!irqs_disabled());  	mp_ops->smp_finish(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h index f90062b0622..224b4262486 100644 --- a/arch/mn10300/include/asm/thread_info.h +++ b/arch/mn10300/include/asm/thread_info.h @@ -165,8 +165,6 @@ void arch_release_thread_info(struct thread_info *ti);  #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */  #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */ -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif /* __KERNEL__ */  #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 84f4e97e307..2da39fb8b3b 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -50,77 +50,19 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  void (*pm_power_off)(void);  EXPORT_SYMBOL(pm_power_off); -#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) -/* - * we use this if we don't have any better idle routine - */ -static void default_idle(void) -{ -	local_irq_disable(); -	if (!need_resched()) -		safe_halt(); -	else -		local_irq_enable(); -} - -#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU  */  /*   * On SMP it's slightly faster (but much more power-consuming!)   * to poll the ->work.need_resched flag instead of waiting for the   * cross-CPU IPI to arrive. Use this option with caution. + * + * tglx: No idea why this depends on HOTPLUG_CPU !?!   */ -static inline void poll_idle(void) -{ -	int oldval; - -	local_irq_enable(); - -	/* -	 * Deal with another CPU just having chosen a thread to -	 * run here: -	 */ -	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - -	if (!oldval) { -		set_thread_flag(TIF_POLLING_NRFLAG); -		while (!need_resched()) -			cpu_relax(); -		clear_thread_flag(TIF_POLLING_NRFLAG); -	} else { -		set_need_resched(); -	} -} -#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */ - -/* - * the idle thread - * - there's no useful work to be done, so just try to conserve power and have - *   a low exit latency (ie sit in a loop waiting for somebody to say that - *   they'd like to reschedule) - */ -void cpu_idle(void) +#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) +void arch_cpu_idle(void)  { -	/* endless idle loop with no priority at all */ -	for (;;) { -		rcu_idle_enter(); -		while (!need_resched()) { -			void (*idle)(void); - -			smp_rmb(); -			if (!idle) { -#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU) -				idle = poll_idle; -#else  /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */ -				idle = default_idle; -#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */ -			} -			idle(); -		} -		rcu_idle_exit(); - -		schedule_preempt_disabled(); -	} +	safe_halt();  } +#endif  void release_segments(struct mm_struct *mm)  { diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c index 5d7e152a23b..a17f9c9c14c 100644 --- a/arch/mn10300/kernel/smp.c +++ b/arch/mn10300/kernel/smp.c @@ -675,7 +675,7 @@ int __init start_secondary(void *unused)  #ifdef CONFIG_GENERIC_CLOCKEVENTS  	init_clockevents();  #endif -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  	return 0;  } @@ -935,8 +935,6 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)  	int timeout;  #ifdef CONFIG_HOTPLUG_CPU -	if (num_online_cpus() == 1) -		disable_hlt();  	if (sleep_mode[cpu])  		run_wakeup_cpu(cpu);  #endif /* CONFIG_HOTPLUG_CPU */ @@ -1003,9 +1001,6 @@ int __cpu_disable(void)  void __cpu_die(unsigned int cpu)  {  	run_sleep_cpu(cpu); - -	if (num_online_cpus() == 1) -		enable_hlt();  }  #ifdef CONFIG_MN10300_CACHE_ENABLED diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h index 07f3212422a..d797acc901e 100644 --- a/arch/openrisc/include/asm/thread_info.h +++ b/arch/openrisc/include/asm/thread_info.h @@ -128,8 +128,6 @@ register struct thread_info *current_thread_info_reg asm("r10");  /* For OpenRISC, this is anything in the LSW other than syscall trace */  #define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP)) -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif /* __KERNEL__ */  #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index 35f92ce51c2..ec6d9d37cef 100644 --- a/arch/openrisc/kernel/Makefile +++ b/arch/openrisc/kernel/Makefile @@ -4,7 +4,7 @@  extra-y	:= head.o vmlinux.lds -obj-y	:= setup.o idle.o or32_ksyms.o process.o dma.o \ +obj-y	:= setup.o or32_ksyms.o process.o dma.o \  	   traps.o time.o irq.o entry.o ptrace.o signal.o \  	   sys_call_table.o diff --git a/arch/openrisc/kernel/idle.c b/arch/openrisc/kernel/idle.c deleted file mode 100644 index 5e8a3b6d6bc..00000000000 --- a/arch/openrisc/kernel/idle.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * OpenRISC idle.c - * - * Linux architectural port borrowing liberally from similar works of - * others.  All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> - * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> - * - *      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. - * - * Idle daemon for or32.  Idle daemon will handle any action - * that needs to be taken when the system becomes idle. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/tick.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/mmu.h> -#include <asm/cache.h> -#include <asm/pgalloc.h> - -void (*powersave) (void) = NULL; - -void cpu_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched()) { -			check_pgt_cache(); -			rmb(); - -			clear_thread_flag(TIF_POLLING_NRFLAG); - -			local_irq_disable(); -			/* Don't trace irqs off for idle */ -			stop_critical_timings(); -			if (!need_resched() && powersave != NULL) -				powersave(); -			start_critical_timings(); -			local_irq_enable(); -			set_thread_flag(TIF_POLLING_NRFLAG); -		} - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} -} diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index d1fb79a36f3..6182832e5b6 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h @@ -77,8 +77,6 @@ struct thread_info {  #define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP |	\  				 _TIF_BLOCKSTEP) -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif /* __KERNEL__ */  #endif /* _ASM_PARISC_THREAD_INFO_H */ diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index d13507246c5..55f92b61418 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -59,28 +59,6 @@  #include <asm/unwind.h>  #include <asm/sections.h> -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			barrier(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -		check_pgt_cache(); -	} -} - -  #define COMMAND_GLOBAL  F_EXTEND(0xfffe0030)  #define CMD_RESET       5       /* reset any module */ diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 6266730efd6..fd1bb1519c2 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -329,7 +329,7 @@ void __init smp_callin(void)  	local_irq_enable();  /* Interrupts have been off until now */ -	cpu_idle();      /* Wait for timer to schedule some work */ +	cpu_startup_entry(CPUHP_ONLINE);  	/* NOTREACHED */  	panic("smp_callin() AAAAaaaaahhhh....\n"); diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 406b7b9a134..8ceea14d6fe 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -182,8 +182,6 @@ static inline bool test_thread_local_flags(unsigned int flags)  #define is_32bit_task()	(1)  #endif -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif	/* !__ASSEMBLY__ */  #endif /* __KERNEL__ */ diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index ea78761aa16..939ea7ef0dc 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -33,11 +33,6 @@  #include <asm/runlatch.h>  #include <asm/smp.h> -#ifdef CONFIG_HOTPLUG_CPU -#define cpu_should_die()	cpu_is_offline(smp_processor_id()) -#else -#define cpu_should_die()	0 -#endif  unsigned long cpuidle_disable = IDLE_NO_OVERRIDE;  EXPORT_SYMBOL(cpuidle_disable); @@ -50,64 +45,38 @@ static int __init powersave_off(char *arg)  }  __setup("powersave=off", powersave_off); -/* - * The body of the idle task. - */ -void cpu_idle(void) +#ifdef CONFIG_HOTPLUG_CPU +void arch_cpu_idle_dead(void)  { -	set_thread_flag(TIF_POLLING_NRFLAG); -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched() && !cpu_should_die()) { -			ppc64_runlatch_off(); - -			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(); - -				/* Don't trace irqs off for idle */ -				stop_critical_timings(); - -				/* check again after disabling irqs */ -				if (!need_resched() && !cpu_should_die()) -					ppc_md.power_save(); - -				start_critical_timings(); - -				/* Some power_save functions return with -				 * interrupts enabled, some don't. -				 */ -				if (irqs_disabled()) -					local_irq_enable(); -				set_thread_flag(TIF_POLLING_NRFLAG); +	sched_preempt_enable_no_resched(); +	cpu_die(); +} +#endif -			} else { -				/* -				 * Go into low thread priority and possibly -				 * low power mode. -				 */ -				HMT_low(); -				HMT_very_low(); -			} -		} +void arch_cpu_idle(void) +{ +	ppc64_runlatch_off(); -		HMT_medium(); -		ppc64_runlatch_on(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		if (cpu_should_die()) { -			sched_preempt_enable_no_resched(); -			cpu_die(); -		} -		schedule_preempt_disabled(); +	if (ppc_md.power_save) { +		ppc_md.power_save(); +		/* +		 * Some power_save functions return with +		 * interrupts enabled, some don't. +		 */ +		if (irqs_disabled()) +			local_irq_enable(); +	} else { +		local_irq_enable(); +		/* +		 * Go into low thread priority and possibly +		 * low power mode. +		 */ +		HMT_low(); +		HMT_very_low();  	} + +	HMT_medium(); +	ppc64_runlatch_on();  }  int powersave_nap; diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 76bd9da8cb7..ee7ac5e6e28 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -669,7 +669,7 @@ __cpuinit void start_secondary(void *unused)  	local_irq_enable(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  	BUG();  } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 536d64579d9..2bc3eddae34 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -61,18 +61,8 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  	return sf->gprs[8];  } -/* - * The idle loop on a S390... - */ -static void default_idle(void) +void arch_cpu_idle(void)  { -	if (cpu_is_offline(smp_processor_id())) -		cpu_die(); -	local_irq_disable(); -	if (need_resched()) { -		local_irq_enable(); -		return; -	}  	local_mcck_disable();  	if (test_thread_flag(TIF_MCCK_PENDING)) {  		local_mcck_enable(); @@ -83,19 +73,15 @@ static void default_idle(void)  	vtime_stop_cpu();  } -void cpu_idle(void) +void arch_cpu_idle_exit(void)  { -	for (;;) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched() && !test_thread_flag(TIF_MCCK_PENDING)) -			default_idle(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		if (test_thread_flag(TIF_MCCK_PENDING)) -			s390_handle_mcck(); -		schedule_preempt_disabled(); -	} +	if (test_thread_flag(TIF_MCCK_PENDING)) +		s390_handle_mcck(); +} + +void arch_cpu_idle_dead(void) +{ +	cpu_die();  }  extern void __kprobes kernel_thread_starter(void); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 8bde89eafd8..8074cb4b7cb 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -714,8 +714,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid)  	set_cpu_online(smp_processor_id(), true);  	inc_irq_stat(CPU_RST);  	local_irq_enable(); -	/* cpu_idle will call schedule for us */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* Upping and downing of CPUs */ diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index a0042acbd98..3fb09359eda 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -158,8 +158,6 @@ void __kprobes vtime_stop_cpu(void)  	unsigned long psw_mask;  	trace_hardirqs_on(); -	/* Don't trace preempt off for idle. */ -	stop_critical_timings();  	/* Wait for external, I/O or machine check interrupt. */  	psw_mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_DAT | @@ -169,9 +167,6 @@ void __kprobes vtime_stop_cpu(void)  	/* Call the assembler magic in entry.S */  	psw_idle(idle, psw_mask); -	/* Reenable preemption tracer. */ -	start_critical_timings(); -  	/* Account time spent with enabled wait psw loaded as idle time. */  	idle->sequence++;  	smp_wmb(); diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 79568466b57..f4c6d02421d 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c @@ -41,24 +41,6 @@ void machine_halt(void) {}  /* If or when software machine-power-off is implemented, add code here. */  void machine_power_off(void) {} -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void __noreturn cpu_idle(void) -{ -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			barrier(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} -} -  void ret_from_fork(void);  void ret_from_kernel_thread(void); diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5e859633ce6..1ea597c6497 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -33,6 +33,7 @@ config SUPERH  	select GENERIC_ATOMIC64  	select GENERIC_IRQ_SHOW  	select GENERIC_SMP_IDLE_THREAD +	select GENERIC_IDLE_POLL_SETUP  	select GENERIC_CLOCKEVENTS  	select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST  	select GENERIC_STRNCPY_FROM_USER @@ -148,9 +149,6 @@ config ARCH_HAS_ILOG2_U32  config ARCH_HAS_ILOG2_U64  	def_bool n -config ARCH_HAS_DEFAULT_IDLE -	def_bool y -  config NO_IOPORT  	def_bool !PCI  	depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \ diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index 7d5ac4e4848..45a93669289 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -207,8 +207,6 @@ static inline bool test_and_clear_restore_sigmask(void)  	return true;  } -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif	/* !__ASSEMBLY__ */  #endif /* __KERNEL__ */ diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 3d5a1b387cc..2ea4483fd72 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -24,98 +24,24 @@  static void (*sh_idle)(void); -static int hlt_counter; - -static int __init nohlt_setup(char *__unused) -{ -	hlt_counter = 1; -	return 1; -} -__setup("nohlt", nohlt_setup); - -static int __init hlt_setup(char *__unused) -{ -	hlt_counter = 0; -	return 1; -} -__setup("hlt", hlt_setup); - -static inline int hlt_works(void) -{ -	return !hlt_counter; -} - -/* - * On SMP it's slightly faster (but much more power-consuming!) - * to poll the ->work.need_resched flag instead of waiting for the - * cross-CPU IPI to arrive. Use this option with caution. - */ -static void poll_idle(void) +void default_idle(void)  { +	set_bl_bit();  	local_irq_enable(); -	while (!need_resched()) -		cpu_relax(); +	/* Isn't this racy ? */ +	cpu_sleep(); +	clear_bl_bit();  } -void default_idle(void) +void arch_cpu_idle_dead(void)  { -	if (hlt_works()) { -		clear_thread_flag(TIF_POLLING_NRFLAG); -		smp_mb__after_clear_bit(); - -		set_bl_bit(); -		if (!need_resched()) { -			local_irq_enable(); -			cpu_sleep(); -		} else -			local_irq_enable(); - -		set_thread_flag(TIF_POLLING_NRFLAG); -		clear_bl_bit(); -	} else -		poll_idle(); +	play_dead();  } -/* - * The idle thread. There's no useful work to be done, so just try to conserve - * power and have a low exit latency (ie sit in a loop waiting for somebody to - * say that they'd like to reschedule) - */ -void cpu_idle(void) +void arch_cpu_idle(void)  { -	unsigned int cpu = smp_processor_id(); - -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched()) { -			check_pgt_cache(); -			rmb(); - -			if (cpu_is_offline(cpu)) -				play_dead(); - -			local_irq_disable(); -			/* Don't trace irqs off for idle */ -			stop_critical_timings(); -			if (cpuidle_idle_call()) -				sh_idle(); -			/* -			 * Sanity check to ensure that sh_idle() returns -			 * with IRQs enabled -			 */ -			WARN_ON(irqs_disabled()); -			start_critical_timings(); -		} - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} +	if (cpuidle_idle_call()) +		sh_idle();  }  void __init select_idle_routine(void) @@ -123,13 +49,8 @@ void __init select_idle_routine(void)  	/*  	 * If a platform has set its own idle routine, leave it alone.  	 */ -	if (sh_idle) -		return; - -	if (hlt_works()) +	if (!sh_idle)  		sh_idle = default_idle; -	else -		sh_idle = poll_idle;  }  void stop_this_cpu(void *unused) diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 2062aa88af4..45696451f0e 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -203,7 +203,7 @@ asmlinkage void __cpuinit start_secondary(void)  	set_cpu_online(cpu, true);  	per_cpu(cpu_state, cpu) = CPU_ONLINE; -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  extern struct { diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index 25849ae3e90..dd3807599bb 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h @@ -132,8 +132,6 @@ register struct thread_info *current_thread_info_reg asm("g6");  #define _TIF_DO_NOTIFY_RESUME_MASK	(_TIF_NOTIFY_RESUME | \  					 _TIF_SIGPENDING) -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #endif /* __KERNEL__ */  #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 269bd92313d..d5e50425107 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -256,8 +256,6 @@ static inline bool test_and_clear_restore_sigmask(void)  	return true;  } -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) -  #define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0)  #define test_thread_64bit_stack(__SP) \  	((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \ diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S index 9365432904d..605c960b2fa 100644 --- a/arch/sparc/kernel/hvtramp.S +++ b/arch/sparc/kernel/hvtramp.S @@ -128,8 +128,7 @@ hv_cpu_startup:  	call		smp_callin  	 nop -	call		cpu_idle -	 mov		0, %o0 +  	call		cpu_panic  	 nop diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 62eede13831..c85241006e3 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -64,23 +64,12 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);  struct task_struct *last_task_used_math = NULL;  struct thread_info *current_set[NR_CPUS]; -/* - * the idle loop on a Sparc... ;) - */ -void cpu_idle(void) +/* Idle loop support. */ +void arch_cpu_idle(void)  { -	set_thread_flag(TIF_POLLING_NRFLAG); - -	/* endless idle loop with no priority at all */ -	for (;;) { -		while (!need_resched()) { -			if (sparc_idle) -				(*sparc_idle)(); -			else -				cpu_relax(); -		} -		schedule_preempt_disabled(); -	} +	if (sparc_idle) +		(*sparc_idle)(); +	local_irq_enable();  }  /* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */ diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index cdb80b2adbe..9fbf0d14a36 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -52,20 +52,17 @@  #include "kstack.h" -static void sparc64_yield(int cpu) +/* Idle loop support on sparc64. */ +void arch_cpu_idle(void)  {  	if (tlb_type != hypervisor) {  		touch_nmi_watchdog(); -		return; -	} - -	clear_thread_flag(TIF_POLLING_NRFLAG); -	smp_mb__after_clear_bit(); - -	while (!need_resched() && !cpu_is_offline(cpu)) { +	} else {  		unsigned long pstate; -		/* Disable interrupts. */ +                /* The sun4v sleeping code requires that we have PSTATE.IE cleared over +                 * the cpu sleep hypervisor call. +                 */  		__asm__ __volatile__(  			"rdpr %%pstate, %0\n\t"  			"andn %0, %1, %0\n\t" @@ -73,7 +70,7 @@ static void sparc64_yield(int cpu)  			: "=&r" (pstate)  			: "i" (PSTATE_IE)); -		if (!need_resched() && !cpu_is_offline(cpu)) +		if (!need_resched() && !cpu_is_offline(smp_processor_id()))  			sun4v_cpu_yield();  		/* Re-enable interrupts. */ @@ -84,36 +81,16 @@ static void sparc64_yield(int cpu)  			: "=&r" (pstate)  			: "i" (PSTATE_IE));  	} - -	set_thread_flag(TIF_POLLING_NRFLAG); +	local_irq_enable();  } -/* The idle loop on sparc64. */ -void cpu_idle(void) -{ -	int cpu = smp_processor_id(); - -	set_thread_flag(TIF_POLLING_NRFLAG); - -	while(1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); - -		while (!need_resched() && !cpu_is_offline(cpu)) -			sparc64_yield(cpu); - -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -  #ifdef CONFIG_HOTPLUG_CPU -		if (cpu_is_offline(cpu)) { -			sched_preempt_enable_no_resched(); -			cpu_play_dead(); -		} -#endif -		schedule_preempt_disabled(); -	} +void arch_cpu_idle_dead() +{ +	sched_preempt_enable_no_resched(); +	cpu_play_dead();  } +#endif  #ifdef CONFIG_COMPAT  static void show_regwindow32(struct pt_regs *regs) diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 9e7e6d71836..e3f2b81c23f 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -369,7 +369,7 @@ void __cpuinit sparc_start_secondary(void *arg)  	local_irq_enable();  	wmb(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  	/* We should never reach here! */  	BUG(); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index ca64d2a86ec..77539eda928 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -127,6 +127,8 @@ void __cpuinit smp_callin(void)  	/* idle thread is expected to have preempt disabled */  	preempt_disable(); + +	cpu_startup_entry(CPUHP_ONLINE);  }  void cpu_panic(void) diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S index da1b781b5e6..2e973a26fbd 100644 --- a/arch/sparc/kernel/trampoline_64.S +++ b/arch/sparc/kernel/trampoline_64.S @@ -407,8 +407,7 @@ after_lock_tlb:  	call		smp_callin  	 nop -	call		cpu_idle -	 mov		0, %o0 +  	call		cpu_panic  	 nop  1:	b,a,pt		%xcc, 1b diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index e9c670d7a7f..ccc8ef37235 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h @@ -153,8 +153,6 @@ extern void _cpu_idle(void);  #define TS_POLLING		0x0004	/* in idle loop but not sleeping */  #define TS_RESTORE_SIGMASK	0x0008	/* restore signal mask in do_signal */ -#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) -  #ifndef __ASSEMBLY__  #define HAVE_SET_RESTORE_SIGMASK	1  static inline void set_restore_sigmask(void) diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index caf93ae1179..80b2a18deb8 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -40,13 +40,11 @@  #include <arch/abi.h>  #include <arch/sim_def.h> -  /*   * Use the (x86) "idle=poll" option to prefer low latency when leaving the   * idle loop over low power while in the idle loop, e.g. if we have   * one thread per core and we want to get threads out of futex waits fast.   */ -static int no_idle_nap;  static int __init idle_setup(char *str)  {  	if (!str) @@ -54,64 +52,19 @@ static int __init idle_setup(char *str)  	if (!strcmp(str, "poll")) {  		pr_info("using polling idle threads.\n"); -		no_idle_nap = 1; -	} else if (!strcmp(str, "halt")) -		no_idle_nap = 0; -	else -		return -1; - -	return 0; +		cpu_idle_poll_ctrl(true); +		return 0; +	} else if (!strcmp(str, "halt")) { +		return 0; +	} +	return -1;  }  early_param("idle", idle_setup); -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) +void arch_cpu_idle(void)  { -	int cpu = smp_processor_id(); - - -	current_thread_info()->status |= TS_POLLING; - -	if (no_idle_nap) { -		while (1) { -			while (!need_resched()) -				cpu_relax(); -			schedule(); -		} -	} - -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) { -			if (cpu_is_offline(cpu)) -				BUG();  /* no HOTPLUG_CPU */ - -			local_irq_disable(); -			__get_cpu_var(irq_stat).idle_timestamp = jiffies; -			current_thread_info()->status &= ~TS_POLLING; -			/* -			 * TS_POLLING-cleared state must be visible before we -			 * test NEED_RESCHED: -			 */ -			smp_mb(); - -			if (!need_resched()) -				_cpu_idle(); -			else -				local_irq_enable(); -			current_thread_info()->status |= TS_POLLING; -		} -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		schedule_preempt_disabled(); -	} +	__get_cpu_var(irq_stat).idle_timestamp = jiffies; +	_cpu_idle();  }  /* diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c index e686c5ac90b..44bab29bf2f 100644 --- a/arch/tile/kernel/smpboot.c +++ b/arch/tile/kernel/smpboot.c @@ -207,9 +207,7 @@ void __cpuinit online_secondary(void)  	/* Set up tile-timer clock-event device on this cpu */  	setup_tile_timer(); -	preempt_enable(); - -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index b462b13c5ba..bbcef522bcb 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -210,33 +210,14 @@ void initial_thread_cb(void (*proc)(void *), void *arg)  	kmalloc_ok = save_kmalloc_ok;  } -void default_idle(void) +void arch_cpu_idle(void)  {  	unsigned long long nsecs; -	while (1) { -		/* endless idle loop with no priority at all */ - -		/* -		 * although we are an idle CPU, we do not want to -		 * get into the scheduler unnecessarily. -		 */ -		if (need_resched()) -			schedule(); - -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		nsecs = disable_timer(); -		idle_sleep(nsecs); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -	} -} - -void cpu_idle(void) -{  	cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); -	default_idle(); +	nsecs = disable_timer(); +	idle_sleep(nsecs); +	local_irq_enable();  }  int __cant_sleep(void) { diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c index 872d7e22d84..7fab86d7c5d 100644 --- a/arch/unicore32/kernel/process.c +++ b/arch/unicore32/kernel/process.c @@ -45,25 +45,10 @@ static const char * const processor_modes[] = {  	"UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR"  }; -void cpu_idle(void) +void arch_cpu_idle(void)  { -	/* endless idle loop with no priority at all */ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched()) { -			local_irq_disable(); -			stop_critical_timings(); -			cpu_do_idle(); -			local_irq_enable(); -			start_critical_timings(); -		} -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} +	cpu_do_idle(); +	local_irq_enable();  }  static char reboot_mode = 'h'; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 15b5cef4aa3..d75b48c11be 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -188,9 +188,6 @@ config GENERIC_CALIBRATE_DELAY  config ARCH_HAS_CPU_RELAX  	def_bool y -config ARCH_HAS_DEFAULT_IDLE -	def_bool y -  config ARCH_HAS_CACHE_LINE_SIZE  	def_bool y diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 2cd056e3ada..a1df6e84691 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -241,8 +241,6 @@ static inline struct thread_info *current_thread_info(void)  					   skip sending interrupt */  #define TS_RESTORE_SIGMASK	0x0008	/* restore signal mask in do_signal() */ -#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) -  #ifndef __ASSEMBLY__  #define HAVE_SET_RESTORE_SIGMASK	1  static inline void set_restore_sigmask(void) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 14ae10031ff..6833bffaadb 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -301,13 +301,7 @@ void exit_idle(void)  }  #endif -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) +void arch_cpu_idle_prepare(void)  {  	/*  	 * If we're the non-boot CPU, nothing set the stack canary up @@ -317,71 +311,40 @@ void cpu_idle(void)  	 * canaries already on the stack wont ever trigger).  	 */  	boot_init_stack_canary(); -	current_thread_info()->status |= TS_POLLING; - -	while (1) { -		tick_nohz_idle_enter(); - -		while (!need_resched()) { -			rmb(); - -			if (cpu_is_offline(smp_processor_id())) -				play_dead(); - -			/* -			 * Idle routines should keep interrupts disabled -			 * from here on, until they go to idle. -			 * Otherwise, idle callbacks can misfire. -			 */ -			local_touch_nmi(); -			local_irq_disable(); - -			enter_idle(); - -			/* Don't trace irqs off for idle */ -			stop_critical_timings(); - -			/* enter_idle() needs rcu for notifiers */ -			rcu_idle_enter(); +} -			if (cpuidle_idle_call()) -				x86_idle(); +void arch_cpu_idle_enter(void) +{ +	local_touch_nmi(); +	enter_idle(); +} -			rcu_idle_exit(); -			start_critical_timings(); +void arch_cpu_idle_exit(void) +{ +	__exit_idle(); +} -			/* In many cases the interrupt that ended idle -			   has already called exit_idle. But some idle -			   loops can be woken up without interrupt. */ -			__exit_idle(); -		} +void arch_cpu_idle_dead(void) +{ +	play_dead(); +} -		tick_nohz_idle_exit(); -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} +/* + * Called from the generic idle code. + */ +void arch_cpu_idle(void) +{ +	if (cpuidle_idle_call()) +		x86_idle();  }  /* - * We use this if we don't have any better - * idle routine.. + * We use this if we don't have any better idle routine..   */  void default_idle(void)  {  	trace_cpu_idle_rcuidle(1, smp_processor_id()); -	current_thread_info()->status &= ~TS_POLLING; -	/* -	 * TS_POLLING-cleared state must be visible before we -	 * test NEED_RESCHED: -	 */ -	smp_mb(); - -	if (!need_resched()) -		safe_halt();	/* enables interrupts racelessly */ -	else -		local_irq_enable(); -	current_thread_info()->status |= TS_POLLING; +	safe_halt();  	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());  }  #ifdef CONFIG_APM_MODULE @@ -411,20 +374,6 @@ void stop_this_cpu(void *dummy)  		halt();  } -/* - * On SMP it's slightly faster (but much more power-consuming!) - * to poll the ->work.need_resched flag instead of waiting for the - * cross-CPU IPI to arrive. Use this option with caution. - */ -static void poll_idle(void) -{ -	trace_cpu_idle_rcuidle(0, smp_processor_id()); -	local_irq_enable(); -	while (!need_resched()) -		cpu_relax(); -	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); -} -  bool amd_e400_c1e_detected;  EXPORT_SYMBOL(amd_e400_c1e_detected); @@ -489,10 +438,10 @@ static void amd_e400_idle(void)  void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)  {  #ifdef CONFIG_SMP -	if (x86_idle == poll_idle && smp_num_siblings > 1) +	if (boot_option_idle_override == IDLE_POLL && smp_num_siblings > 1)  		pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");  #endif -	if (x86_idle) +	if (x86_idle || boot_option_idle_override == IDLE_POLL)  		return;  	if (cpu_has_amd_erratum(amd_erratum_400)) { @@ -517,8 +466,8 @@ static int __init idle_setup(char *str)  	if (!strcmp(str, "poll")) {  		pr_info("using polling idle threads\n"); -		x86_idle = poll_idle;  		boot_option_idle_override = IDLE_POLL; +		cpu_idle_poll_ctrl(true);  	} else if (!strcmp(str, "halt")) {  		/*  		 * When the boot option of idle=halt is added, halt is diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 9f190a2a00e..9c73b51817e 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -284,7 +284,7 @@ notrace static void __cpuinit start_secondary(void *unused)  	x86_cpuinit.setup_percpu_clockev();  	wmb(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  void __init smp_store_boot_cpu_info(void) diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 0d466d7c717..8ff37995d54 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -95,7 +95,7 @@ static void __cpuinit cpu_bringup(void)  static void __cpuinit cpu_bringup_and_idle(void)  {  	cpu_bringup(); -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  static int xen_smp_intr_init(unsigned int cpu) diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 5cd82e9f601..1c85323f01d 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -105,19 +105,9 @@ void coprocessor_flush_all(struct thread_info *ti)  /*   * Powermanagement idle function, if any is provided by the platform.   */ - -void cpu_idle(void) +void arch_cpu_idle(void)  { -	local_irq_enable(); - -	/* endless idle loop with no priority at all */ -	while (1) { -		rcu_idle_enter(); -		while (!need_resched()) -			platform_idle(); -		rcu_idle_exit(); -		schedule_preempt_disabled(); -	} +	platform_idle();  }  /* diff --git a/include/linux/cpu.h b/include/linux/cpu.h index ce7a074f251..c6f6e0839b6 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -212,4 +212,20 @@ static inline int disable_nonboot_cpus(void) { return 0; }  static inline void enable_nonboot_cpus(void) {}  #endif /* !CONFIG_PM_SLEEP_SMP */ +enum cpuhp_state { +	CPUHP_OFFLINE, +	CPUHP_ONLINE, +}; + +void cpu_startup_entry(enum cpuhp_state state); +void cpu_idle(void); + +void cpu_idle_poll_ctrl(bool enable); + +void arch_cpu_idle(void); +void arch_cpu_idle_prepare(void); +void arch_cpu_idle_enter(void); +void arch_cpu_idle_exit(void); +void arch_cpu_idle_dead(void); +  #endif /* _LINUX_CPU_H_ */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 01c7d85bcaa..981ab688725 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2457,6 +2457,47 @@ static inline int spin_needbreak(spinlock_t *lock)  }  /* + * Idle thread specific functions to determine the need_resched + * polling state. We have two versions, one based on TS_POLLING in + * thread_info.status and one based on TIF_POLLING_NRFLAG in + * thread_info.flags + */ +#ifdef TS_POLLING +static inline int tsk_is_polling(struct task_struct *p) +{ +	return task_thread_info(p)->status & TS_POLLING; +} +static inline void current_set_polling(void) +{ +	current_thread_info()->status |= TS_POLLING; +} + +static inline void current_clr_polling(void) +{ +	current_thread_info()->status &= ~TS_POLLING; +	smp_mb__after_clear_bit(); +} +#elif defined(TIF_POLLING_NRFLAG) +static inline int tsk_is_polling(struct task_struct *p) +{ +	return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); +} +static inline void current_set_polling(void) +{ +	set_thread_flag(TIF_POLLING_NRFLAG); +} + +static inline void current_clr_polling(void) +{ +	clear_thread_flag(TIF_POLLING_NRFLAG); +} +#else +static inline int tsk_is_polling(struct task_struct *p) { return 0; } +static inline void current_set_polling(void) { } +static inline void current_clr_polling(void) { } +#endif + +/*   * Thread group CPU time accounting.   */  void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times); diff --git a/init/main.c b/init/main.c index ea73e1eb361..12c366944db 100644 --- a/init/main.c +++ b/init/main.c @@ -386,7 +386,7 @@ static noinline void __init_refok rest_init(void)  	init_idle_bootup_task(current);  	schedule_preempt_disabled();  	/* Call into cpu_idle with preempt disabled */ -	cpu_idle(); +	cpu_startup_entry(CPUHP_ONLINE);  }  /* Check for early params. */ diff --git a/kernel/Makefile b/kernel/Makefile index bbde5f1a448..d1574d47cf2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -24,6 +24,7 @@ endif  obj-y += sched/  obj-y += power/ +obj-y += cpu/  obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o  obj-$(CONFIG_FREEZER) += freezer.o diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile new file mode 100644 index 00000000000..59ab052ef7a --- /dev/null +++ b/kernel/cpu/Makefile @@ -0,0 +1 @@ +obj-y	= idle.o diff --git a/kernel/cpu/idle.c b/kernel/cpu/idle.c new file mode 100644 index 00000000000..168cf407a25 --- /dev/null +++ b/kernel/cpu/idle.c @@ -0,0 +1,107 @@ +/* + * Generic entry point for the idle threads + */ +#include <linux/sched.h> +#include <linux/cpu.h> +#include <linux/tick.h> +#include <linux/mm.h> + +#include <asm/tlb.h> + +#include <trace/events/power.h> + +static int __read_mostly cpu_idle_force_poll; + +void cpu_idle_poll_ctrl(bool enable) +{ +	if (enable) { +		cpu_idle_force_poll++; +	} else { +		cpu_idle_force_poll--; +		WARN_ON_ONCE(cpu_idle_force_poll < 0); +	} +} + +#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP +static int __init cpu_idle_poll_setup(char *__unused) +{ +	cpu_idle_force_poll = 1; +	return 1; +} +__setup("nohlt", cpu_idle_poll_setup); + +static int __init cpu_idle_nopoll_setup(char *__unused) +{ +	cpu_idle_force_poll = 0; +	return 1; +} +__setup("hlt", cpu_idle_nopoll_setup); +#endif + +static inline int cpu_idle_poll(void) +{ +	trace_cpu_idle_rcuidle(0, smp_processor_id()); +	local_irq_enable(); +	while (!need_resched()) +		cpu_relax(); +	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); +	return 1; +} + +/* Weak implementations for optional arch specific functions */ +void __weak arch_cpu_idle_prepare(void) { } +void __weak arch_cpu_idle_enter(void) { } +void __weak arch_cpu_idle_exit(void) { } +void __weak arch_cpu_idle_dead(void) { } +void __weak arch_cpu_idle(void) +{ +	cpu_idle_force_poll = 1; +} + +/* + * Generic idle loop implementation + */ +static void cpu_idle_loop(void) +{ +	while (1) { +		tick_nohz_idle_enter(); + +		while (!need_resched()) { +			check_pgt_cache(); +			rmb(); + +			if (cpu_is_offline(smp_processor_id())) +				arch_cpu_idle_dead(); + +			local_irq_disable(); +			arch_cpu_idle_enter(); + +			if (cpu_idle_force_poll) { +				cpu_idle_poll(); +			} else { +				current_clr_polling(); +				if (!need_resched()) { +					stop_critical_timings(); +					rcu_idle_enter(); +					arch_cpu_idle(); +					WARN_ON_ONCE(irqs_disabled()); +					rcu_idle_exit(); +					start_critical_timings(); +				} else { +					local_irq_enable(); +				} +				current_set_polling(); +			} +			arch_cpu_idle_exit(); +		} +		tick_nohz_idle_exit(); +		schedule_preempt_disabled(); +	} +} + +void cpu_startup_entry(enum cpuhp_state state) +{ +	current_set_polling(); +	arch_cpu_idle_prepare(); +	cpu_idle_loop(); +} diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ebdb1954121..c70a8814a76 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -512,11 +512,6 @@ static inline void init_hrtick(void)   * the target CPU.   */  #ifdef CONFIG_SMP - -#ifndef tsk_is_polling -#define tsk_is_polling(t) 0 -#endif -  void resched_task(struct task_struct *p)  {  	int cpu;  |