diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 9727f59e8f954cb0aa0c93c2d18a24f0664aadd1..685cbf4637691a44abc06ebc46b6cf11a831a7a9 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -602,7 +602,7 @@ void openpic_request_IPIs(void)
  *   -- Cort
  */
 
-void __init do_openpic_setup_cpu(void)
+void __devinit do_openpic_setup_cpu(void)
 {
  	int i;
 	u32 msk = 1 << smp_hw_index[smp_processor_id()];
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 5ac73276f493191850b2e50e3e88ab83468ab483..52150568c47baa834ab1de00a091da22658242d0 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -48,15 +48,17 @@ struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-unsigned long cache_decay_ticks;
-static int max_cpus __initdata = NR_CPUS;
-unsigned long cpu_online_map;
+unsigned int prof_multiplier[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 };
+unsigned int prof_counter[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 };
+unsigned long cache_decay_ticks = HZ/100;
+unsigned long cpu_online_map = 1UL;
+unsigned long cpu_possible_map = 1UL;
 int smp_hw_index[NR_CPUS];
-static struct smp_ops_t *smp_ops;
 struct thread_info *secondary_ti;
 
+/* SMP operations for this machine */
+static struct smp_ops_t *smp_ops;
+
 /* all cpu mappings are 1-1 -- Cort */
 volatile unsigned long cpu_callin_map[NR_CPUS];
 
@@ -70,10 +72,6 @@ void smp_call_function_interrupt(void);
 static int __smp_call_function(void (*func) (void *info), void *info,
 			       int wait, int target);
 
-#ifdef CONFIG_PPC_ISERIES
-extern void smp_iSeries_space_timers( unsigned nr );
-#endif
-
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  * 
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
@@ -291,6 +289,7 @@ void smp_call_function_interrupt(void)
 		atomic_inc(&call_data->finished);
 }
 
+#if 0 /* Old boot code. */
 void __init smp_boot_cpus(void)
 {
 	int i, cpu_nr;
@@ -556,3 +555,156 @@ static int __init maxcpus(char *str)
 }
 
 __setup("maxcpus=", maxcpus);
+#else /* New boot code */
+/* FIXME: Do this properly for all archs --RR */
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int timebase_upper = 0, timebase_lower = 0;
+
+void __devinit
+smp_generic_give_timebase(void)
+{
+	spin_lock(&timebase_lock);
+	do {
+		timebase_upper = get_tbu();
+		timebase_lower = get_tbl();
+	} while (timebase_upper != get_tbu());
+	spin_unlock(&timebase_lock);
+
+	while (timebase_upper || timebase_lower)
+		rmb();
+}
+
+void __devinit
+smp_generic_take_timebase(void)
+{
+	int done = 0;
+
+	while (!done) {
+		spin_lock(&timebase_lock);
+		if (timebase_upper || timebase_lower) {
+			set_tb(timebase_upper, timebase_lower);
+			timebase_upper = 0;
+			timebase_lower = 0;
+			done = 1;
+		}
+		spin_unlock(&timebase_lock);
+	}
+}
+
+static void __devinit smp_store_cpu_info(int id)
+{
+        struct cpuinfo_PPC *c = &cpu_data[id];
+
+	/* assume bogomips are same for everything */
+        c->loops_per_jiffy = loops_per_jiffy;
+        c->pvr = mfspr(PVR);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	int num_cpus;
+
+	/* 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();
+	cpu_possible_map = (1 << num_cpus)-1;
+
+	if (smp_ops->space_timers)
+		smp_ops->space_timers(num_cpus);
+}
+
+int __init setup_profiling_timer(unsigned int multiplier)
+{
+	return 0;
+}
+
+/* Processor coming up starts here */
+int __devinit start_secondary(void *unused)
+{
+	int cpu;
+
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+
+	cpu = smp_processor_id();
+        smp_store_cpu_info(cpu);
+	set_dec(tb_ticks_per_jiffy);
+	cpu_callin_map[cpu] = 1;
+
+	printk("CPU %i done callin...\n", cpu);
+	smp_ops->setup_cpu(cpu);
+	printk("CPU %i done setup...\n", cpu);
+	smp_ops->take_timebase();
+	printk("CPU %i done timebase take...\n", cpu);
+
+	return cpu_idle(NULL);
+}
+
+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 = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
+	if (IS_ERR(p))
+		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
+
+	init_idle(p, cpu);
+	unhash_process(p);
+
+	secondary_ti = p->thread_info;
+	p->thread_info->cpu = cpu;
+
+	/*
+	 * There was a cache flush loop here to flush the cache
+	 * to memory for the first 8MB of RAM.  The cache flush
+	 * has been pushed into the kick_cpu function for those
+	 * platforms that need it.
+	 */
+
+	/* wake up cpu */
+	smp_ops->kick_cpu(cpu);
+		
+	/*
+	 * wait to see if the cpu made a callin (is actually up).
+	 * use this value that I found through experimentation.
+	 * -- Cort
+	 */
+	for (c = 1000; c && !cpu_callin_map[cpu]; c--)
+		udelay(100);
+
+	if (!cpu_callin_map[cpu]) {
+		sprintf(buf, "didn't find cpu %u", cpu);
+		if (ppc_md.progress) ppc_md.progress(buf, 0x360+cpu);
+		printk("Processor %u is stuck.\n", cpu);
+		return -ENOENT;
+	}
+
+	sprintf(buf, "found cpu %u", cpu);
+	if (ppc_md.progress) ppc_md.progress(buf, 0x350+cpu);
+	printk("Processor %d found.\n", cpu);
+
+	smp_ops->give_timebase();
+	set_bit(cpu, &cpu_online_map);
+	return 0;
+}
+
+void smp_cpus_done(unsigned int max_cpus)
+{
+	smp_ops->setup_cpu(0);
+}
+#endif
diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c
index 4d28976651fe1a098a694e08068c2cacdcb672e2..80e6584c93d96ae62bf48f615300409858450db3 100644
--- a/arch/ppc/platforms/chrp_smp.c
+++ b/arch/ppc/platforms/chrp_smp.c
@@ -50,59 +50,61 @@ smp_chrp_probe(void)
 	return smp_chrp_cpu_nr;
 }
 
-static void __init
+static void __devinit
 smp_chrp_kick_cpu(int nr)
 {
 	*(unsigned long *)KERNELBASE = nr;
 	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
 }
 
-static void __init
+static void __devinit
 smp_chrp_setup_cpu(int cpu_nr)
 {
-	static atomic_t ready = ATOMIC_INIT(1);
-	static volatile int frozen = 0;
-
-	/* FIXME: Hotplug cpu breaks all this --RR */
-	if (cpu_nr == 0) {
-		/* wait for all the others */
-		while (atomic_read(&ready) < num_online_cpus())
-			barrier();
-		atomic_set(&ready, 1);
-		/* freeze the timebase */
-		call_rtas("freeze-time-base", 0, 1, NULL);
-		mb();
-		frozen = 1;
-		/* XXX assumes this is not a 601 */
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		while (atomic_read(&ready) < num_online_cpus())
-			barrier();
-		/* thaw the timebase again */
-		call_rtas("thaw-time-base", 0, 1, NULL);
-		mb();
-		frozen = 0;
-		smp_tb_synchronized = 1;
-	} else {
-		atomic_inc(&ready);
-		while (!frozen)
-			barrier();
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		mb();
-		atomic_inc(&ready);
-		while (frozen)
-			barrier();
-	}
-
 	if (OpenPIC_Addr)
 		do_openpic_setup_cpu();
 }
 
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int timebase_upper = 0, timebase_lower = 0;
+
+void __devinit
+smp_chrp_give_timebase(void)
+{
+	spin_lock(&timebase_lock);
+	call_rtas("freeze-time-base", 0, 1, NULL);
+	timebase_upper = get_tbu();
+	timebase_lower = get_tbl();
+	spin_unlock(&timebase_lock);
+
+	while (timebase_upper || timebase_lower)
+		rmb();
+	call_rtas("thaw-time-base", 0, 1, NULL);
+}
+
+void __devinit
+smp_chrp_take_timebase(void)
+{
+	int done = 0;
+
+	while (!done) {
+		spin_lock(&timebase_lock);
+		if (timebase_upper || timebase_lower) {
+			set_tb(timebase_upper, timebase_lower);
+			timebase_upper = 0;
+			timebase_lower = 0;
+			done = 1;
+		}
+		spin_unlock(&timebase_lock);
+	}
+	printk("CPU %i taken timebase\n", smp_processor_id());
+}
+
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops __chrpdata = {
-	smp_openpic_message_pass,
-	smp_chrp_probe,
-	smp_chrp_kick_cpu,
-	smp_chrp_setup_cpu,
+	.message_pass = smp_openpic_message_pass,
+	.probe = smp_chrp_probe,
+	.kick_cpu = smp_chrp_kick_cpu,
+	.setup_cpu = smp_chrp_setup_cpu,
+	.give_timebase = smp_chrp_give_timebase,
+	.take_timebase = smp_chrp_take_timebase,
 };
diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
index db86f459abd4c70abee86c5a361803e14f3bffa2..feeee01f669b736aa6face157caf4fec1ddd7591 100644
--- a/arch/ppc/platforms/gemini_setup.c
+++ b/arch/ppc/platforms/gemini_setup.c
@@ -528,6 +528,8 @@ static struct smp_ops_t gemini_smp_ops = {
 	smp_gemini_probe,
 	smp_gemini_kick_cpu,
 	smp_gemini_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
diff --git a/arch/ppc/platforms/iSeries_smp.c b/arch/ppc/platforms/iSeries_smp.c
index 055a4f58ce50eeef620aa1c0117f388110f2f59b..1a22a035125e6492ec57f64eaf0a8e61bcf89ee6 100644
--- a/arch/ppc/platforms/iSeries_smp.c
+++ b/arch/ppc/platforms/iSeries_smp.c
@@ -117,7 +117,7 @@ static void smp_iSeries_setup_cpu(int nr)
 	set_dec( xPaca[nr].default_decr );
 }
 
-void smp_iSeries_space_timers( unsigned nr )
+static void smp_iSeries_space_timers(unsigned nr)
 {
 	unsigned offset,i;
 	
@@ -131,6 +131,9 @@ struct smp_ops_t iSeries_smp_ops = {
    smp_iSeries_message_pass,
    smp_iSeries_probe,
    smp_iSeries_kick_cpu,
-   smp_iSeries_setup_cpu
+   smp_iSeries_setup_cpu,
+   smp_iSeries_space_timers,
+   .give_timebase = smp_generic_give_timebase,
+   .take_timebase = smp_generic_take_timebase,
 };
 
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
index 0ca0e3af9f58107574cd2fdf5f1b8569b0e72c23..cd5804be4e88bdbdc12b42912704ad343a66eb50 100644
--- a/arch/ppc/platforms/pmac_smp.c
+++ b/arch/ppc/platforms/pmac_smp.c
@@ -612,6 +612,8 @@ struct smp_ops_t psurge_smp_ops __pmacdata = {
 	smp_psurge_probe,
 	smp_psurge_kick_cpu,
 	smp_psurge_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 
 /* Core99 Macs (dual G4s) */
@@ -620,4 +622,6 @@ struct smp_ops_t core99_smp_ops __pmacdata = {
 	smp_core99_probe,
 	smp_core99_kick_cpu,
 	smp_core99_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
diff --git a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c
index 640c6164fbd0ec9f226d6951e758a5600d4aacd7..73d74c2d0e9989e297d8d020b3d80e6b4ab38b5c 100644
--- a/arch/ppc/platforms/pplus_setup.c
+++ b/arch/ppc/platforms/pplus_setup.c
@@ -309,6 +309,8 @@ static struct smp_ops_t pplus_smp_ops = {
 	smp_pplus_probe,
 	smp_pplus_kick_cpu,
 	smp_pplus_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 9ab36cbf3f10f6a17daa1d4fb57bceb6caba6f9a..25721ad975b7b9a7b7bc68f52f26d41ac512a56e 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -756,6 +756,8 @@ static struct smp_ops_t prep_smp_ops __prepdata = {
 	smp_prep_probe,
 	smp_prep_kick_cpu,
 	smp_prep_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index f5218fdb73c2c82aba737f4bfd380860e537f45b..2c32dc7aa949d09e3092882d707d3217235c1486 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -6,6 +6,7 @@
 #define _PPC_MACHDEP_H
 
 #include <linux/config.h>
+#include <linux/init.h>
 
 #ifdef CONFIG_APUS
 #include <asm-m68k/machdep.h>
@@ -129,7 +130,14 @@ struct smp_ops_t {
 	int   (*probe)(void);
 	void  (*kick_cpu)(int nr);
 	void  (*setup_cpu)(int nr);
+	void  (*space_timers)(int nr);
+	void  (*take_timebase)(void);
+	void  (*give_timebase)(void);
 };
+
+/* Poor default implementations */
+extern void __devinit smp_generic_give_timebase(void);
+extern void __devinit smp_generic_take_timebase(void);
 #endif /* CONFIG_SMP */
 
 #endif /* _PPC_MACHDEP_H */
diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
index 6c58f14684a1c86d23042913d9abb005e869fd18..f5e99d565d32deb20998503181e6081b57bbc9bb 100644
--- a/include/asm-ppc/smp.h
+++ b/include/asm-ppc/smp.h
@@ -16,6 +16,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/errno.h>
 
 #ifdef CONFIG_SMP
 
@@ -31,11 +32,11 @@ struct cpuinfo_PPC {
 
 extern struct cpuinfo_PPC cpu_data[];
 extern unsigned long cpu_online_map;
+extern unsigned long cpu_possible_map;
 extern unsigned long smp_proc_in_lock[];
 extern volatile unsigned long cpu_callin_map[];
 extern int smp_tb_synchronized;
 
-extern void smp_store_cpu_info(int id);
 extern void smp_send_tlb_invalidate(int);
 extern void smp_send_xmon_break(int cpu);
 struct pt_regs;
@@ -48,6 +49,7 @@ extern void smp_local_timer_interrupt(struct pt_regs *);
 #define smp_processor_id() (current_thread_info()->cpu)
 
 #define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
+#define cpu_possible(cpu) (cpu_possible_map & (1<<(cpu)))
 
 extern inline unsigned int num_online_cpus(void)
 {
@@ -62,6 +64,8 @@ extern inline int any_online_cpu(unsigned int mask)
 	return -1;
 }
 
+extern int __cpu_up(unsigned int cpu);
+
 extern int smp_hw_index[];
 #define hard_smp_processor_id() (smp_hw_index[smp_processor_id()])