Commit 1ef8b835 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: cpu-idle notifier

This patch introduces a notifier chain for cpu idle.  There are two events
CPU_IDLE and CPU_NOT_IDLE that are called just before the cpu goes to sleep
and right after the cpu woke up again.  The notifier is used to simplify the
no-hz-timer-in-idle feature and the virtual cpu timers.  In addition the
virtual cpu timer functions have been moved to arch/s390/kernel/vtime.c, which
gives a nice separation between the timer functions related to real time and
the timer functions related to virtual cpu time.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6ac48313
...@@ -23,6 +23,8 @@ obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o ...@@ -23,6 +23,8 @@ obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
obj-$(CONFIG_ARCH_S390_31) += entry.o reipl.o obj-$(CONFIG_ARCH_S390_31) += entry.o reipl.o
obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o
obj-$(CONFIG_VIRT_TIMER) += vtime.o
# #
# This is just to get the dependencies... # This is just to get the dependencies...
# #
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -41,9 +43,7 @@ ...@@ -41,9 +43,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/irq.h> #include <asm/irq.h>
#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ)
#include <asm/timer.h> #include <asm/timer.h>
#endif
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
...@@ -68,13 +68,39 @@ unsigned long thread_saved_pc(struct task_struct *tsk) ...@@ -68,13 +68,39 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
} }
/* /*
* The idle loop on a S390... * Need to know about CPUs going idle?
*/ */
static struct notifier_block *idle_chain;
int register_idle_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&idle_chain, nb);
}
EXPORT_SYMBOL(register_idle_notifier);
int unregister_idle_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&idle_chain, nb);
}
EXPORT_SYMBOL(unregister_idle_notifier);
void do_monitor_call(struct pt_regs *regs, long interruption_code)
{
/* disable monitor call class 0 */
__ctl_clear_bit(8, 15);
notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
(void *)(long) smp_processor_id());
}
/*
* The idle loop on a S390...
*/
void default_idle(void) void default_idle(void)
{ {
psw_t wait_psw; psw_t wait_psw;
unsigned long reg; unsigned long reg;
int cpu, rc;
local_irq_disable(); local_irq_disable();
if (need_resched()) { if (need_resched()) {
...@@ -83,15 +109,18 @@ void default_idle(void) ...@@ -83,15 +109,18 @@ void default_idle(void)
return; return;
} }
#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ) /* CPU is going idle. */
/* cpu = smp_processor_id();
* hook to stop timers that should not tick while CPU is idle rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
*/ if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
if (stop_timers()) { BUG();
if (rc != NOTIFY_OK) {
local_irq_enable(); local_irq_enable();
return; return;
} }
#endif
/* enable monitor call class 0 */
__ctl_set_bit(8, 15);
/* /*
* Wait for external, I/O or machine check interrupt and * Wait for external, I/O or machine check interrupt and
......
...@@ -19,9 +19,6 @@ ...@@ -19,9 +19,6 @@
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
#include <net/arp.h> #include <net/arp.h>
#endif #endif
#ifdef CONFIG_VIRT_TIMER
#include <asm/timer.h>
#endif
/* /*
* memory management * memory management
......
...@@ -509,6 +509,7 @@ void __init smp_check_cpus(unsigned int max_cpus) ...@@ -509,6 +509,7 @@ void __init smp_check_cpus(unsigned int max_cpus)
* Activate a secondary processor. * Activate a secondary processor.
*/ */
extern void init_cpu_timer(void); extern void init_cpu_timer(void);
extern void init_cpu_vtimer(void);
extern int pfault_init(void); extern int pfault_init(void);
extern int pfault_token(void); extern int pfault_token(void);
...@@ -518,6 +519,9 @@ int __devinit start_secondary(void *cpuvoid) ...@@ -518,6 +519,9 @@ int __devinit start_secondary(void *cpuvoid)
cpu_init(); cpu_init();
/* init per CPU timer */ /* init per CPU timer */
init_cpu_timer(); init_cpu_timer();
#ifdef CONFIG_VIRT_TIMER
init_cpu_vtimer();
#endif
#ifdef CONFIG_PFAULT #ifdef CONFIG_PFAULT
/* Enable pfault pseudo page faults on this cpu. */ /* Enable pfault pseudo page faults on this cpu. */
pfault_init(); pfault_init();
......
This diff is collapsed.
...@@ -64,9 +64,7 @@ extern void pfault_fini(void); ...@@ -64,9 +64,7 @@ extern void pfault_fini(void);
extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
static ext_int_info_t ext_int_pfault; static ext_int_info_t ext_int_pfault;
#endif #endif
#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_VIRT_TIMER)
extern pgm_check_handler_t do_monitor_call; extern pgm_check_handler_t do_monitor_call;
#endif
#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
...@@ -620,9 +618,8 @@ void __init trap_init(void) ...@@ -620,9 +618,8 @@ void __init trap_init(void)
#endif /* CONFIG_ARCH_S390X */ #endif /* CONFIG_ARCH_S390X */
pgm_check_table[0x15] = &operand_exception; pgm_check_table[0x15] = &operand_exception;
pgm_check_table[0x1C] = &privileged_op; pgm_check_table[0x1C] = &privileged_op;
#if defined(CONFIG_VIRT_TIMER) || defined(CONFIG_NO_IDLE_HZ)
pgm_check_table[0x40] = &do_monitor_call; pgm_check_table[0x40] = &do_monitor_call;
#endif
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {
/* /*
* First try to get pfault pseudo page faults going. * First try to get pfault pseudo page faults going.
......
This diff is collapsed.
...@@ -319,6 +319,16 @@ static inline void disabled_wait(unsigned long code) ...@@ -319,6 +319,16 @@ static inline void disabled_wait(unsigned long code)
#endif /* __s390x__ */ #endif /* __s390x__ */
} }
/*
* CPU idle notifier chain.
*/
#define CPU_IDLE 0
#define CPU_NOT_IDLE 1
struct notifier_block;
int register_idle_notifier(struct notifier_block *nb);
int unregister_idle_notifier(struct notifier_block *nb);
#endif #endif
#endif /* __ASM_S390_PROCESSOR_H */ #endif /* __ASM_S390_PROCESSOR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment