summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/smp.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-09-10 21:13:13 +1000
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-10 10:15:11 -0700
commit31139971b3dc9fbb2e8a8572fb81e6e8470f363a (patch)
tree644fc6833fe6e18d00dbc8b6b281f77e7b923d35 /arch/ppc/kernel/smp.c
parentbb0bb3b6596cdb08adb0b72453cc67d48e139c2c (diff)
[PATCH] ppc32: support hotplug cpu on powermacs
This allows cpus to be off-lined on 32-bit SMP powermacs. When a cpu is off-lined, it is put into sleep mode with interrupts disabled. It can be on-lined again by asserting its soft-reset pin, which is connected to a GPIO pin. With this I can off-line the second cpu in my dual G4 powermac, which means that I can then suspend the machine (the suspend/resume code refuses to suspend if more than one cpu is online, and making it cope with multiple cpus is surprisingly messy). Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc/kernel/smp.c')
-rw-r--r--arch/ppc/kernel/smp.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index e70b587b9e5..726fe7ce174 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -45,6 +45,7 @@ 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);
@@ -286,7 +287,8 @@ static void __devinit smp_store_cpu_info(int id)
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());
@@ -308,6 +310,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if (smp_ops->space_timers)
smp_ops->space_timers(num_cpus);
+
+ for_each_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));
+ p->thread_info->cpu = cpu;
+ idle_tasks[cpu] = p;
+ }
}
void __devinit smp_prepare_boot_cpu(void)
@@ -334,12 +347,17 @@ int __devinit start_secondary(void *unused)
set_dec(tb_ticks_per_jiffy);
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);
+
+ spin_lock(&call_lock);
+ cpu_set(cpu, cpu_online_map);
+ spin_unlock(&call_lock);
+
+ local_irq_enable();
cpu_idle();
return 0;
@@ -347,17 +365,11 @@ int __devinit start_secondary(void *unused)
int __cpu_up(unsigned int cpu)
{
- 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 */
- p = fork_idle(cpu);
- if (IS_ERR(p))
- panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
- secondary_ti = p->thread_info;
- p->thread_info->cpu = cpu;
+ secondary_ti = idle_tasks[cpu]->thread_info;
+ mb();
/*
* There was a cache flush loop here to flush the cache
@@ -389,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;
}