X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fkernel%2Fprocess.c;h=73cb6baeb5259c1a39277273099cc709a61a373e;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=252e652cd5a0079c2043c1a1d7e78a7b8d5bdb0e;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 252e652cd..73cb6baeb 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -16,6 +16,8 @@ */ #include +#include +#include #include #include #include @@ -33,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -40,9 +44,7 @@ #include #include #include -#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ) #include -#endif asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -67,13 +69,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) { psw_t wait_psw; unsigned long reg; + int cpu, rc; local_irq_disable(); if (need_resched()) { @@ -82,14 +110,22 @@ void default_idle(void) return; } -#if defined(CONFIG_VIRT_TIMER) || defined (CONFIG_NO_IDLE_HZ) - /* - * hook to stop timers that should not tick while CPU is idle - */ - if (stop_timers()) { + /* CPU is going idle. */ + cpu = smp_processor_id(); + rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu); + if (rc != NOTIFY_OK && rc != NOTIFY_DONE) + BUG(); + if (rc != NOTIFY_OK) { local_irq_enable(); return; } + + /* enable monitor call class 0 */ + __ctl_set_bit(8, 15); + +#ifdef CONFIG_HOTPLUG_CPU + if (cpu_is_offline(smp_processor_id())) + cpu_die(); #endif /* @@ -292,12 +328,12 @@ asmlinkage long sys_clone(struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; - int *parent_tidptr, *child_tidptr; + int __user *parent_tidptr, *child_tidptr; clone_flags = regs.gprs[3]; newsp = regs.orig_gpr2; - parent_tidptr = (int *) regs.gprs[4]; - child_tidptr = (int *) regs.gprs[5]; + parent_tidptr = (int __user *) regs.gprs[4]; + child_tidptr = (int __user *) regs.gprs[5]; if (!newsp) newsp = regs.gprs[15]; return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, @@ -328,12 +364,12 @@ asmlinkage long sys_execve(struct pt_regs regs) int error; char * filename; - filename = getname((char *) regs.orig_gpr2); + filename = getname((char __user *) regs.orig_gpr2); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char **) regs.gprs[3], - (char **) regs.gprs[4], ®s); + error = do_execve(filename, (char __user * __user *) regs.gprs[3], + (char __user * __user *) regs.gprs[4], ®s); if (error == 0) { current->ptrace &= ~PT_DTRACE; current->thread.fp_regs.fpc = 0; @@ -385,12 +421,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->regs.per_info = current->thread.per_info; } -/* - * These bracket the sleeping functions.. - */ -#define first_sched ((unsigned long) scheduling_functions_start_here) -#define last_sched ((unsigned long) scheduling_functions_end_here) - unsigned long get_wchan(struct task_struct *p) { unsigned long r14, r15, bc; @@ -413,12 +443,10 @@ unsigned long get_wchan(struct task_struct *p) #else r14 = *(unsigned long *) (bc+112); #endif - if (r14 < first_sched || r14 >= last_sched) + if (!in_sched_functions(r14)) return r14; bc = (*(unsigned long *) bc) & PSW_ADDR_INSN; } while (count++ < 16); return 0; } -#undef last_sched -#undef first_sched