upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / arch / ia64 / kernel / process.c
index 488c79d..00de4e4 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998-2003 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
+ * 04/11/17 Ashok Raj  <ashok.raj@intel.com> Added CPU Hotplug Support
  */
 #define __KERNEL_SYSCALLS__    /* see <asm/unistd.h> */
 #include <linux/config.h>
@@ -25,6 +26,7 @@
 #include <linux/unistd.h>
 #include <linux/efi.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 #include <asm/cpu.h>
 #include <asm/delay.h>
@@ -40,6 +42,8 @@
 #include <asm/user.h>
 #include <asm/diskdump.h>
 
+#include "entry.h"
+
 #ifdef CONFIG_PERFMON
 # include <asm/perfmon.h>
 #endif
@@ -47,6 +51,7 @@
 #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);
@@ -171,7 +176,9 @@ 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;
@@ -179,16 +186,20 @@ static int __init nohalt_setup(char * str)
 }
 __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)
+               if (can_do_pal_halt)
                        safe_halt();
                else
                        cpu_relax();
@@ -199,27 +210,20 @@ default_idle (void)
 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;
 
-       /* We shouldn't have to disable interrupts while dead, but
-        * some interrupts just don't seem to go away, and this makes
-        * it "work" for testing purposes. */
        max_xtp();
        local_irq_disable();
-       /* Death loop */
-       while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
-               cpu_relax();
-
+       idle_task_exit();
+       ia64_jump_to_sal(&sal_boot_rendez_state[this_cpu]);
        /*
-        * Enable timer interrupts from now on
-        * Not required if we put processor in SAL_BOOT_RENDEZ mode.
+        * The above is a point of no-return, the processor is
+        * expected to be in SAL loop now.
         */
-       local_flush_tlb_all();
-       cpu_set(smp_processor_id(), cpu_online_map);
-       wmb();
-       ia64_cpu_local_tick ();
-       local_irq_enable();
+       BUG();
 }
 #else
 static inline void play_dead(void)
@@ -228,8 +232,36 @@ static inline void play_dead(void)
 }
 #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;
 
@@ -242,19 +274,17 @@ cpu_idle (void *unused)
                while (!need_resched()) {
                        void (*idle)(void);
 
+                       if (__get_cpu_var(cpu_idle_state))
+                               __get_cpu_var(cpu_idle_state) = 0;
+
+                       rmb();
                        if (mark_idle)
                                (*mark_idle)(1);
-                       /*
-                        * Mark this as an RCU critical section so that
-                        * synchronize_kernel() in the unload path waits
-                        * for our completion.
-                        */
-                       rcu_read_lock();
+
                        idle = pm_idle;
                        if (!idle)
                                idle = default_idle;
                        (*idle)();
-                       rcu_read_unlock();
                }
 
                if (mark_idle)
@@ -618,7 +648,7 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
        return 1;       /* f0-f31 are always valid so we always return 1 */
 }
 
-asmlinkage long
+long
 sys_execve (char __user *filename, char __user * __user *argv, char __user * __user *envp,
            struct pt_regs *regs)
 {
@@ -655,7 +685,7 @@ 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;
-
+       regs.sw.pr = (1 << PRED_KERNEL_STACK);
        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs.pt, 0, NULL, NULL);
 }
 EXPORT_SYMBOL(kernel_thread);