fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ppc / kernel / smp.c
index c28fbf3..96a5597 100644 (file)
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -26,7 +25,6 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/hardirq.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/thread_info.h>
 #include <asm/tlbflush.h>
 #include <asm/xmon.h>
+#include <asm/machdep.h>
 
-int smp_threads_ready;
 volatile int smp_commenced;
 int smp_tb_synchronized;
 struct cpuinfo_PPC cpu_data[NR_CPUS];
-struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-DEFINE_PER_CPU(unsigned int, prof_multiplier);
-DEFINE_PER_CPU(unsigned int, prof_counter);
-unsigned long cache_decay_ticks = HZ/100;
 cpumask_t cpu_online_map;
 cpumask_t cpu_possible_map;
 int smp_hw_index[NR_CPUS];
 struct thread_info *secondary_ti;
+static struct task_struct *idle_tasks[NR_CPUS];
 
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(cpu_possible_map);
 
 /* SMP operations for this machine */
-static struct smp_ops_t *smp_ops;
+struct smp_ops_t *smp_ops;
 
 /* all cpu mappings are 1-1 -- Cort */
 volatile unsigned long cpu_callin_map[NR_CPUS];
 
 int start_secondary(void *);
-extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
 static int __smp_call_function(void (*func) (void *info), void *info,
                               int wait, int target);
@@ -79,28 +73,18 @@ extern void __save_cpu_setup(void);
 #define PPC_MSG_XMON_BREAK     3
 
 static inline void
-smp_message_pass(int target, int msg, unsigned long data, int wait)
+smp_message_pass(int target, int msg)
 {
-       if (smp_ops){
+       if (smp_ops) {
                atomic_inc(&ipi_sent);
-               smp_ops->message_pass(target,msg,data,wait);
+               smp_ops->message_pass(target, msg);
        }
 }
 
 /*
  * Common functions
  */
-void smp_local_timer_interrupt(struct pt_regs * regs)
-{
-       int cpu = smp_processor_id();
-
-       if (!--per_cpu(prof_counter, cpu)) {
-               update_process_times(user_mode(regs));
-               per_cpu(prof_counter, cpu) = per_cpu(prof_multiplier, cpu);
-       }
-}
-
-void smp_message_recv(int msg, struct pt_regs *regs)
+void smp_message_recv(int msg)
 {
        atomic_inc(&ipi_recv);
 
@@ -116,7 +100,7 @@ void smp_message_recv(int msg, struct pt_regs *regs)
                break;
 #ifdef CONFIG_XMON
        case PPC_MSG_XMON_BREAK:
-               xmon(regs);
+               xmon(get_irq_regs());
                break;
 #endif /* CONFIG_XMON */
        default:
@@ -133,8 +117,8 @@ void smp_message_recv(int msg, struct pt_regs *regs)
  */
 void smp_send_tlb_invalidate(int cpu)
 {
-       if ( PVR_VER(mfspr(PVR)) == 8 )
-               smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0);
+       if ( PVR_VER(mfspr(SPRN_PVR)) == 8 )
+               smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB);
 }
 
 void smp_send_reschedule(int cpu)
@@ -150,13 +134,13 @@ void smp_send_reschedule(int cpu)
         */
        /* This is only used if `cpu' is running an idle task,
           so it will reschedule itself anyway... */
-       smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0);
+       smp_message_pass(cpu, PPC_MSG_RESCHEDULE);
 }
 
 #ifdef CONFIG_XMON
 void smp_send_xmon_break(int cpu)
 {
-       smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0);
+       smp_message_pass(cpu, PPC_MSG_XMON_BREAK);
 }
 #endif /* CONFIG_XMON */
 
@@ -177,7 +161,7 @@ void smp_send_stop(void)
  * static memory requirements. It also looks cleaner.
  * Stolen from the i386 version.
  */
-static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(call_lock);
 
 static struct call_data_struct {
        void (*func) (void *info);
@@ -239,7 +223,7 @@ static int __smp_call_function(void (*func) (void *info), void *info,
        spin_lock(&call_lock);
        call_data = &data;
        /* Send a message to all other CPUs and wait for them to respond */
-       smp_message_pass(target, PPC_MSG_CALL_FUNCTION, 0, 0);
+       smp_message_pass(target, PPC_MSG_CALL_FUNCTION);
 
        /* Wait for response */
        timeout = 1000000;
@@ -297,20 +281,18 @@ static void __devinit smp_store_cpu_info(int id)
 
        /* assume bogomips are same for everything */
         c->loops_per_jiffy = loops_per_jiffy;
-        c->pvr = mfspr(PVR);
-       per_cpu(prof_counter, id) = 1;
-       per_cpu(prof_multiplier, id) = 1;
+        c->pvr = mfspr(SPRN_PVR);
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       int num_cpus, i;
+       int num_cpus, i, cpu;
+       struct task_struct *p;
 
        /* Fixup boot cpu */
         smp_store_cpu_info(smp_processor_id());
        cpu_callin_map[smp_processor_id()] = 1;
 
-       smp_ops = ppc_md.smp_ops;
        if (smp_ops == NULL) {
                printk("SMP not supported on this machine.\n");
                return;
@@ -318,14 +300,26 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 
        /* Probe platform for CPUs: always linear. */
        num_cpus = smp_ops->probe();
+       
+       if (num_cpus < 2)
+               smp_tb_synchronized = 1;
+       
        for (i = 0; i < num_cpus; ++i)
                cpu_set(i, cpu_possible_map);
 
        /* Backup CPU 0 state */
        __save_cpu_setup();
 
-       if (smp_ops->space_timers)
-               smp_ops->space_timers(num_cpus);
+       for_each_possible_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+               /* create a process for the processor */
+               p = fork_idle(cpu);
+               if (IS_ERR(p))
+                       panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
+               task_thread_info(p)->cpu = cpu;
+               idle_tasks[cpu] = p;
+       }
 }
 
 void __devinit smp_prepare_boot_cpu(void)
@@ -350,38 +344,32 @@ int __devinit start_secondary(void *unused)
        cpu = smp_processor_id();
         smp_store_cpu_info(cpu);
        set_dec(tb_ticks_per_jiffy);
+       preempt_disable();
        cpu_callin_map[cpu] = 1;
 
-       printk("CPU %i done callin...\n", cpu);
+       printk("CPU %d done callin...\n", cpu);
        smp_ops->setup_cpu(cpu);
-       printk("CPU %i done setup...\n", cpu);
-       local_irq_enable();
+       printk("CPU %d done setup...\n", cpu);
        smp_ops->take_timebase();
-       printk("CPU %i done timebase take...\n", cpu);
+       printk("CPU %d done timebase take...\n", cpu);
 
-       return cpu_idle(NULL);
+       spin_lock(&call_lock);
+       cpu_set(cpu, cpu_online_map);
+       spin_unlock(&call_lock);
+
+       local_irq_enable();
+
+       cpu_idle();
+       return 0;
 }
 
 int __cpu_up(unsigned int cpu)
 {
-       struct pt_regs regs;
-       struct task_struct *p;
        char buf[32];
        int c;
 
-       /* create a process for the processor */
-       /* only regs.msr is actually used, and 0 is OK for it */
-       memset(&regs, 0, sizeof(struct pt_regs));
-       p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-       if (IS_ERR(p))
-               panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-       wake_up_forked_process(p);
-
-       init_idle(p, cpu);
-       unhash_process(p);
-
-       secondary_ti = p->thread_info;
-       p->thread_info->cpu = cpu;
+       secondary_ti = task_thread_info(idle_tasks[cpu]);
+       mb();
 
        /*
         * There was a cache flush loop here to flush the cache
@@ -413,7 +401,11 @@ int __cpu_up(unsigned int cpu)
        printk("Processor %d found.\n", cpu);
 
        smp_ops->give_timebase();
-       cpu_set(cpu, cpu_online_map);
+
+       /* Wait until cpu puts itself in the online map */
+       while (!cpu_online(cpu))
+               cpu_relax();
+
        return 0;
 }