X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fkernel%2Fsmp.c;h=96a55972b986bd7103270ceeabd037e21edbb4bb;hb=refs%2Fheads%2Fvserver;hp=c28fbf398391c73a871efef14d98f193f4a32c70;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index c28fbf398..96a55972b 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -8,7 +8,6 @@ * */ -#include #include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -35,33 +33,29 @@ #include #include #include +#include -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(®s, 0, sizeof(struct pt_regs)); - p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 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; }