*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#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);
#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)
{
atomic_inc(&ipi_recv);
*/
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)
*/
/* 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 */
* 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);
bitmask. --RR */
if (num_online_cpus() <= 1)
return 0;
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
return __smp_call_function(func, info, wait, MSG_ALL_BUT_SELF);
}
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;
/* 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;
/* 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)
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
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;
}