X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fia64%2Fkernel%2Fprocess.c;h=2447665e8d56f254b219ef76b18499410fdd6f02;hb=refs%2Fheads%2Fvserver;hp=0d245cbcd1f63050e9e04ba08471667c1d55dfba;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 0d245cbcd..2447665e8 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -3,10 +3,12 @@ * * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang + * 04/11/17 Ashok Raj Added CPU Hotplug Support + * + * 2005-10-07 Keith Owens + * Add notify_die() hooks. */ -#define __KERNEL_SYSCALLS__ /* see */ -#include - +#include #include #include #include @@ -14,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -22,17 +25,25 @@ #include #include #include +#include +#include +#include #include #include #include +#include +#include #include #include #include +#include #include #include #include +#include "entry.h" + #ifdef CONFIG_PERFMON # include #endif @@ -40,7 +51,10 @@ #include "sigframe.h" void (*ia64_mark_idle)(int); +static DEFINE_PER_CPU(unsigned int, cpu_idle_state); +unsigned long boot_option_idle_override = 0; +EXPORT_SYMBOL(boot_option_idle_override); void ia64_do_show_stack (struct unw_frame_info *info, void *arg) @@ -68,12 +82,12 @@ void show_stack (struct task_struct *task, unsigned long *sp) { if (!task) - unw_init_running(ia64_do_show_stack, 0); + unw_init_running(ia64_do_show_stack, NULL); else { struct unw_frame_info info; unw_init_from_blocked_task(&info, task); - ia64_do_show_stack(&info, 0); + ia64_do_show_stack(&info, NULL); } } @@ -90,7 +104,9 @@ show_regs (struct pt_regs *regs) { unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; - printk("\nPid: %d, CPU %d, comm: %20s\n", current->pid, smp_processor_id(), current->comm); + print_modules(); + printk("\nPid: %d[#%u], CPU %d, comm: %20s\n", + current->pid, current->xid, smp_processor_id(), current->comm); printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", regs->cr_ipsr, regs->cr_ifs, ip, print_tainted()); print_symbol("ip is at %s\n", ip); @@ -131,7 +147,7 @@ show_regs (struct pt_regs *regs) ndirty = (regs->loadrs >> 19); bsp = ia64_rse_skip_regs((unsigned long *) regs->ar_bspstore, ndirty); for (i = 0; i < sof; ++i) { - get_user(val, ia64_rse_skip_regs(bsp, i)); + get_user(val, (unsigned long __user *) ia64_rse_skip_regs(bsp, i)); printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val, ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } @@ -159,57 +175,139 @@ do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall ia64_do_signal(oldset, scr, in_syscall); } -static int pal_halt = 1; +static int pal_halt = 1; +static int can_do_pal_halt = 1; + static int __init nohalt_setup(char * str) { - pal_halt = 0; + pal_halt = can_do_pal_halt = 0; 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) { - unsigned long pmu_active = ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_PP | IA64_PSR_UP); - - while (!need_resched()) - if (pal_halt && !pmu_active) + local_irq_enable(); + while (!need_resched()) { + if (can_do_pal_halt) safe_halt(); + else + cpu_relax(); + } +} + +#ifdef CONFIG_HOTPLUG_CPU +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + extern void ia64_cpu_local_tick (void); + unsigned int this_cpu = smp_processor_id(); + + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + max_xtp(); + local_irq_disable(); + idle_task_exit(); + ia64_jump_to_sal(&sal_boot_rendez_state[this_cpu]); + /* + * The above is a point of no-return, the processor is + * expected to be in SAL loop now. + */ + BUG(); } +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + +void cpu_idle_wait(void) +{ + unsigned int cpu, this_cpu = get_cpu(); + cpumask_t map; + + set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); + put_cpu(); + + cpus_clear(map); + for_each_online_cpu(cpu) { + per_cpu(cpu_idle_state, cpu) = 1; + cpu_set(cpu, map); + } + + __get_cpu_var(cpu_idle_state) = 0; + + wmb(); + do { + ssleep(1); + for_each_online_cpu(cpu) { + if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) + cpu_clear(cpu, map); + } + cpus_and(map, map, cpu_online_map); + } while (!cpus_empty(map)); +} +EXPORT_SYMBOL_GPL(cpu_idle_wait); void __attribute__((noreturn)) -cpu_idle (void *unused) +cpu_idle (void) { void (*mark_idle)(int) = ia64_mark_idle; + int cpu = smp_processor_id(); /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; + 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; + } + if (!need_resched()) { + void (*idle)(void); #ifdef CONFIG_SMP - if (!need_resched()) min_xtp(); #endif + if (__get_cpu_var(cpu_idle_state)) + __get_cpu_var(cpu_idle_state) = 0; - while (!need_resched()) { + rmb(); if (mark_idle) (*mark_idle)(1); - (*idle)(); - } - - if (mark_idle) - (*mark_idle)(0); + idle = pm_idle; + if (!idle) + idle = default_idle; + (*idle)(); + if (mark_idle) + (*mark_idle)(0); #ifdef CONFIG_SMP - normal_xtp(); + normal_xtp(); #endif + } + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); + if (cpu_is_offline(cpu)) + play_dead(); } } @@ -233,7 +331,7 @@ ia64_save_extra (struct task_struct *task) #endif #ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(ia64_task_regs(task))) + if (IS_IA32_PROCESS(task_pt_regs(task))) ia32_save_state(task); #endif } @@ -258,7 +356,7 @@ ia64_load_extra (struct task_struct *task) #endif #ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(ia64_task_regs(task))) + if (IS_IA32_PROCESS(task_pt_regs(task))) ia32_load_state(task); #endif } @@ -393,10 +491,14 @@ copy_thread (int nr, unsigned long clone_flags, * If we're cloning an IA32 task then save the IA32 extra * state from the current task to the new task */ - if (IS_IA32_PROCESS(ia64_task_regs(current))) { + if (IS_IA32_PROCESS(task_pt_regs(current))) { ia32_save_state(p); if (clone_flags & CLONE_SETTLS) retval = ia32_clone_tls(p, child_ptregs); + + /* Copy partially mapped page list */ + if (!retval) + retval = ia32_copy_partial_page_list(p, clone_flags); } #endif @@ -555,31 +657,23 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) return 1; /* f0-f31 are always valid so we always return 1 */ } -asmlinkage long -sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) +long +sys_execve (char __user *filename, char __user * __user *argv, char __user * __user *envp, + struct pt_regs *regs) { + char *fname; int error; - filename = getname(filename); - error = PTR_ERR(filename); - if (IS_ERR(filename)) + fname = getname(filename); + error = PTR_ERR(fname); + if (IS_ERR(fname)) goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); + error = do_execve(fname, argv, envp, regs); + putname(fname); out: return error; } -void -ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter) -{ - set_personality(PER_LINUX); - if (elf_ex->e_flags & EF_IA_64_LINUX_EXECUTABLE_STACK) - current->thread.flags |= IA64_THREAD_XSTACK; - else - current->thread.flags &= ~IA64_THREAD_XSTACK; -} - pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { @@ -600,8 +694,9 @@ kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; - - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL); + regs.sw.pr = (1 << PRED_KERNEL_STACK); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s.pt, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); @@ -610,7 +705,7 @@ int kernel_thread_helper (int (*fn)(void *), void *arg) { #ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(ia64_task_regs(current))) { + if (IS_IA32_PROCESS(task_pt_regs(current))) { /* A kernel thread is always a 64-bit process. */ current->thread.map_base = DEFAULT_MAP_BASE; current->thread.task_size = DEFAULT_TASK_SIZE; @@ -630,6 +725,13 @@ flush_thread (void) /* drop floating-point and debug-register state if it exists: */ current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); ia64_drop_fpu(current); +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(task_pt_regs(current))) { + ia32_drop_partial_page_list(current); + current->thread.task_size = IA32_PAGE_OFFSET; + set_fs(USER_DS); + } +#endif } /* @@ -639,6 +741,7 @@ flush_thread (void) void exit_thread (void) { + ia64_drop_fpu(current); #ifdef CONFIG_PERFMON /* if needed, stop monitoring and flush state to perfmon context */ @@ -649,6 +752,8 @@ exit_thread (void) if (current->thread.flags & IA64_THREAD_DBG_VALID) pfm_release_debug_registers(current); #endif + if (IS_IA32_PROCESS(task_pt_regs(current))) + ia32_drop_partial_page_list(current); } unsigned long @@ -657,11 +762,6 @@ get_wchan (struct task_struct *p) struct unw_frame_info info; unsigned long ip; int count = 0; - /* - * These bracket the sleeping functions.. - */ -# define first_sched ((unsigned long) scheduling_functions_start_here) -# define last_sched ((unsigned long) scheduling_functions_end_here) /* * Note: p may not be a blocked task (it could be current or @@ -676,12 +776,10 @@ get_wchan (struct task_struct *p) if (unw_unwind(&info) < 0) return 0; unw_get_ip(&info, &ip); - if (ip < first_sched || ip >= last_sched) + if (!in_sched_functions(ip)) return ip; } while (count++ < 16); return 0; -# undef first_sched -# undef last_sched } void @@ -710,19 +808,17 @@ cpu_halt (void) void machine_restart (char *restart_cmd) { - (*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0); + (void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0); + (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL); } -EXPORT_SYMBOL(machine_restart); - void machine_halt (void) { + (void) notify_die(DIE_MACHINE_HALT, "", NULL, 0, 0, 0); cpu_halt(); } -EXPORT_SYMBOL(machine_halt); - void machine_power_off (void) { @@ -731,4 +827,3 @@ machine_power_off (void) machine_halt(); } -EXPORT_SYMBOL(machine_power_off);