diff mbox

[UPDATED,21/27] sparc32, smpboot: Use generic SMP booting infrastructure

Message ID 20120602151348.GA17409@merkur.ravnborg.org
State RFC
Delegated to: David Miller
Headers show

Commit Message

Sam Ravnborg June 2, 2012, 3:13 p.m. UTC
> 
> > I will try to dive into this and see if I on the sparc32 side
> > can make leon behave like the other platforms, and then 
> > unify some of the smp cpu boot stuff such that we then
> > can introduce the generalization from your patch.

This is what I came up with.
I modelled this over your patch-set to make it
simpler to convert to the generic scheme.

I realised a bit more how CPU's are started up on sparc32.
So I think all of leon, sun4m and sun4d should work with this.

But my SUN box is defunct atm. so I have not tested it.
Comments appreciated!

PS. I used the ugly __names for now.
As soon as you have found a better set of names this should
be fixed here too.

	Sam

--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Srivatsa S. Bhat June 2, 2012, 3:58 p.m. UTC | #1
On 06/02/2012 08:43 PM, Sam Ravnborg wrote:

>>
>>> I will try to dive into this and see if I on the sparc32 side
>>> can make leon behave like the other platforms, and then 
>>> unify some of the smp cpu boot stuff such that we then
>>> can introduce the generalization from your patch.
> 
> This is what I came up with.
> I modelled this over your patch-set to make it
> simpler to convert to the generic scheme.
> 


Thanks a lot for doing this :-)

> I realised a bit more how CPU's are started up on sparc32.
> So I think all of leon, sun4m and sun4d should work with this.
> 
> But my SUN box is defunct atm. so I have not tested it.
> Comments appreciated!
> 
> PS. I used the ugly __names for now.
> As soon as you have found a better set of names this should
> be fixed here too.
>


As I mentioned in my other mail, I am thinking of changing them to
arch_cpu_pre_starting(), arch_cpu_pre_online() and arch_cpu_post_online().
Let me know what you think of those names.

Would you kindly add a changelog and your sign-off to this patch?

> 
> diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
> index 291bb5d..2bc1c6d 100644
> --- a/arch/sparc/kernel/kernel.h
> +++ b/arch/sparc/kernel/kernel.h
> @@ -48,6 +48,10 @@ extern void sun4m_init_IRQ(void);
>  extern void sun4m_unmask_profile_irq(void);
>  extern void sun4m_clear_profile_irq(int cpu);
> 
> +/* sun4m_smp.c */
> +void sun4m_cpu_pre_starting(void);
> +void sun4m_cpu_pre_online(void);
> +
>  /* sun4d_irq.c */
>  extern spinlock_t sun4d_imsk_lock;
> 
> @@ -60,6 +64,14 @@ extern int show_sun4d_interrupts(struct seq_file *, void *);
>  extern void sun4d_distribute_irqs(void);
>  extern void sun4d_free_irq(unsigned int irq, void *dev_id);
> 
> +/* sun4d_smp.c */
> +void sun4d_cpu_pre_starting(void);
> +void sun4d_cpu_pre_online(void);
> +
> +/* leon_smp.c */
> +void leon_cpu_pre_starting(void);
> +void leon_cpu_pre_online(void);
> +
>  /* head_32.S */
>  extern unsigned int t_nmi[];
>  extern unsigned int linux_trap_ipi15_sun4d[];
> diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
> index 0f3fb6d..0b028b3 100644
> --- a/arch/sparc/kernel/leon_smp.c
> +++ b/arch/sparc/kernel/leon_smp.c
> @@ -69,31 +69,20 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
>  	return val;
>  }
> 
> -void __cpuinit leon_callin(void)
> +void __cpuinit leon_cpu_pre_starting(void)
>  {
> -	int cpuid = hard_smp_processor_id();
> -
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
>  	leon_configure_cache_smp();
> +}
> 
> -	notify_cpu_starting(cpuid);
> -
> -	/* Get our local ticker going. */
> -	register_percpu_ce(cpuid);
> -
> -	calibrate_delay();
> -	smp_store_cpu_info(cpuid);
> 
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
> +void __cpuinit cpu_cpu_pre_starting(void *unused)


Shouldn't this be leon_cpu_pre_online()? And the parameters
should be consistent too (here it expects a void*, but it is
called with no arguments...)

> +{
> +	int cpuid = hard_smp_processor_id();
> 
> -	/*
> -	 * Unblock the master CPU _only_ when the scheduler state
> -	 * of all secondary CPUs will be up-to-date, so after
> -	 * the SMP initialization the master will be just allowed
> -	 * to call the scheduler code.
> -	 * Allow master to continue.
> +	/* Allow master to continue. The master will then give us the
> +	 * go-ahead by setting the smp_commenced_mask and will wait without
> +	 * timeouts until our setup is completed fully (signified by
> +	 * our bit being set in the cpu_online_mask).
>  	 */
>  	do_swap(&cpu_callin_map[cpuid], 1);
> 
> @@ -110,9 +99,6 @@ void __cpuinit leon_callin(void)
> 
>  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
>  		mb();
> -
> -	local_irq_enable();
> -	set_cpu_online(cpuid, true);
>  }
> 
>  /*
> diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
> index 79db45e..2e2990f 100644
> --- a/arch/sparc/kernel/smp_32.c
> +++ b/arch/sparc/kernel/smp_32.c
> @@ -20,6 +20,7 @@
>  #include <linux/seq_file.h>
>  #include <linux/cache.h>
>  #include <linux/delay.h>
> +#include <linux/cpu.h>
> 
>  #include <asm/ptrace.h>
>  #include <linux/atomic.h>
> @@ -32,8 +33,10 @@
>  #include <asm/cacheflush.h>
>  #include <asm/tlbflush.h>
>  #include <asm/cpudata.h>
> +#include <asm/timer.h>
>  #include <asm/leon.h>
> 
> +#include "kernel.h"
>  #include "irq.h"
> 
>  volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
> @@ -294,6 +297,89 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
>  	return ret;
>  }
> 
> +void __cpuinit __cpu_pre_starting(void *unused)
> +{
> +	local_ops->cache_all();
> +	local_ops->tlb_all();
> +
> +	switch(sparc_cpu_model) {
> +	case sun4m:
> +		sun4m_cpu_pre_starting();


Wouldn't it be better to have a provision to pass the
pointer down to these functions as well?

> +		break;
> +	case sun4d:
> +		sun4d_cpu_pre_starting();
> +		break;
> +	case sparc_leon:
> +		leon_cpu_pre_starting();
> +		break;
> +	default:
> +		BUG();
> +	}
> +}
> +
> +void __cpuinit __cpu_pre_online(void *unused)
> +{
> +	unsigned int cpuid = hard_smp_processor_id();
> +
> +	register_percpu_ce(cpuid);
> +
> +	calibrate_delay();
> +	smp_store_cpu_info(cpuid);
> +
> +	local_ops->cache_all();
> +	local_ops->tlb_all();
> +
> +	switch(sparc_cpu_model) {
> +	case sun4m:
> +		sun4m_cpu_pre_online();
> +		break;
> +	case sun4d:
> +		sun4d_cpu_pre_online();
> +		break;
> +	case sparc_leon:
> +		leon_cpu_pre_starting();


Shouldn't this be leon_cpu_pre_online()?

> +		break;
> +	default:
> +		BUG();
> +	}
> +}
> +
> +void __cpuinit sparc_start_secondary(void *unused)
> +{
> +	unsigned int cpu;
> +
> +	/*
> +	 * SMP booting is extremely fragile in some architectures. So run
> +	 * the cpu initialization code first before anything else.
> +	 */
> +	__cpu_pre_starting(NULL);
> +


Why not pass the pointer to __cpu_pre_starting() as well as the rest of
the functions?

> +	preempt_disable();
> +	cpu = smp_processor_id();
> +
> +	/* Invoke the CPU_STARTING notifier callbacks */
> +	notify_cpu_starting(cpu);
> +
> +	__cpu_pre_online(NULL);
> +
> +	/* Set the CPU in the cpu_online_mask */
> +	set_cpu_online(cpu, true);
> +
> +	/* Enable local interrupts now */
> +	local_irq_enable();
> +
> +	wmb();
> +	cpu_idle();
> +
> +	/* We should never reach here! */
> +	BUG();
> +}
> +
> +void __cpuinit smp_callin(void)
> +{
> +	sparc_start_secondary(NULL);
> +}
> +
>  void smp_bogo(struct seq_file *m)
>  {
>  	int i;
> diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
> index ddaea31..bfbbc46 100644
> --- a/arch/sparc/kernel/sun4d_smp.c
> +++ b/arch/sparc/kernel/sun4d_smp.c
> @@ -50,10 +50,9 @@ static inline void show_leds(int cpuid)
>  			      "i" (ASI_M_CTL));
>  }
> 
> -void __cpuinit smp4d_callin(void)
> +void __cpuinit sun4d_cpu_pre_starting(void)
>  {
>  	int cpuid = hard_smp_processor_id();
> -	unsigned long flags;
> 
>  	/* Show we are alive */
>  	cpu_leds[cpuid] = 0x6;
> @@ -61,24 +60,14 @@ void __cpuinit smp4d_callin(void)
> 
>  	/* Enable level15 interrupt, disable level14 interrupt for now */
>  	cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
> +}
> 
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
> -
> -	notify_cpu_starting(cpuid);
> -	/*
> -	 * Unblock the master CPU _only_ when the scheduler state
> -	 * of all secondary CPUs will be up-to-date, so after
> -	 * the SMP initialization the master will be just allowed
> -	 * to call the scheduler code.
> -	 */
> -	/* Get our local ticker going. */
> -	register_percpu_ce(cpuid);
> +void __cpuinit sun4d_cpu_pre_online(void)
> +{
> +	unsigned long flags;
> +	int cpuid;
> 
> -	calibrate_delay();
> -	smp_store_cpu_info(cpuid);
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
> +	cpuid = hard_smp_processor_id();
> 
>  	/* Allow master to continue. */
>  	sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
> @@ -106,16 +95,12 @@ void __cpuinit smp4d_callin(void)
>  	local_ops->cache_all();
>  	local_ops->tlb_all();
> 
> -	local_irq_enable();	/* We don't allow PIL 14 yet */
> -
>  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
>  		barrier();
> 
>  	spin_lock_irqsave(&sun4d_imsk_lock, flags);
>  	cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
>  	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
> -	set_cpu_online(cpuid, true);
> -
>  }
> 
>  /*
> diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
> index 128af73..0cf6b4f 100644
> --- a/arch/sparc/kernel/sun4m_smp.c
> +++ b/arch/sparc/kernel/sun4m_smp.c
> @@ -34,30 +34,19 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
>  	return val;
>  }
> 
> -void __cpuinit smp4m_callin(void)
> +void __cpuinit sun4m_cpu_pre_starting(void)
>  {
> -	int cpuid = hard_smp_processor_id();
> -
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
> -
> -	notify_cpu_starting(cpuid);
> -
> -	register_percpu_ce(cpuid);
> -
> -	calibrate_delay();
> -	smp_store_cpu_info(cpuid);
> +}
> 
> -	local_ops->cache_all();
> -	local_ops->tlb_all();
> +void __cpuinit sun4m_cpu_pre_online(void)
> +{
> +	int cpuid = hard_smp_processor_id();
> 
> -	/*
> -	 * Unblock the master CPU _only_ when the scheduler state
> -	 * of all secondary CPUs will be up-to-date, so after
> -	 * the SMP initialization the master will be just allowed
> -	 * to call the scheduler code.
> +	/* Allow master to continue. The master will then give us the
> +	 * go-ahead by setting the smp_commenced_mask and will wait without
> +	 * timeouts until our setup is completed fully (signified by
> +	 * our bit being set in the cpu_online_mask).
>  	 */
> -	/* Allow master to continue. */
>  	swap_ulong(&cpu_callin_map[cpuid], 1);
> 
>  	/* XXX: What's up with all the flushes? */
> @@ -75,10 +64,6 @@ void __cpuinit smp4m_callin(void)
> 
>  	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
>  		mb();
> -
> -	local_irq_enable();
> -
> -	set_cpu_online(cpuid, true);
>  }
> 
>  /*
> diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S
> index af27aca..6cdb08c 100644
> --- a/arch/sparc/kernel/trampoline_32.S
> +++ b/arch/sparc/kernel/trampoline_32.S
> @@ -79,18 +79,15 @@ cpu3_startup:
>  	 nop
> 
>  	/* Start this processor. */
> -	call	smp4m_callin
> +	call	smp_callin
>  	 nop
> 
> -	b,a	smp_do_cpu_idle
> +	b,a	smp_panic
> 
>  	.text
>  	.align	4
> 
> -smp_do_cpu_idle:
> -	call	cpu_idle
> -	 mov	0, %o0
> -
> +smp_panic:
>  	call	cpu_panic
>  	 nop
> 
> @@ -144,10 +141,10 @@ sun4d_cpu_startup:
>  	 nop
> 
>  	/* Start this processor. */
> -	call	smp4d_callin
> +	call	smp_callin
>  	 nop
> 
> -	b,a	smp_do_cpu_idle
> +	b,a	smp_panic
> 
>  	__CPUINIT
>  	.align	4
> @@ -201,7 +198,7 @@ leon_smp_cpu_startup:
>  	 nop
> 
>  	/* Start this processor. */
> -	call	leon_callin
> +	call	smp_callin


I still didn't get how this solves the original problem of
not having sparc_cpu_model set to sparc_leon. You mentioned
that by the time we reach leon_smp_cpu_startup, that variable
is not set. Even inside leon_smp_cpu_startup, I don't immediately
see where it is set. Am I missing something?

>  	 nop
> 
> -	b,a	smp_do_cpu_idle
> +	b,a	smp_panic
> 


Regards,
Srivatsa S. Bhat

--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sam Ravnborg June 2, 2012, 4:23 p.m. UTC | #2
> 
> As I mentioned in my other mail, I am thinking of changing them to
> arch_cpu_pre_starting(), arch_cpu_pre_online() and arch_cpu_post_online().
> Let me know what you think of those names.
Much better than "__" - so if none of the guys that excel in core
code objects go for that.

> Would you kindly add a changelog and your sign-off to this patch?
Will do in next revision.

...

Thanks for the throughfull review.
I will address all points - including passing the pointer down,
as I assume you have some future plans with that pointer.

> 
> I still didn't get how this solves the original problem of
> not having sparc_cpu_model set to sparc_leon. You mentioned
> that by the time we reach leon_smp_cpu_startup, that variable
> is not set. Even inside leon_smp_cpu_startup, I don't immediately
> see where it is set. Am I missing something?

After looking more closely at the code it is my understanding
that a leon CPU when started will actually jump to the reset
vector and start from there.
So the secondary CPU's will run long time after
sparc_cpu_model is set so we can safely use it.

The sun based cpu will in comparsion jump to
an address supplied to a prom call - so they do not
jump to the reset vector.
But they also have sparc_cpu_model set so no problem there
either.

All this are my deductions from reading the code - but this
is not an area I have looked at otherwise..

I may not find time today to cook up a new version of
the patch - but then you will have it tomorrow.

	Sam
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Srivatsa S. Bhat June 2, 2012, 4:34 p.m. UTC | #3
On 06/02/2012 09:53 PM, Sam Ravnborg wrote:

>>
>> As I mentioned in my other mail, I am thinking of changing them to
>> arch_cpu_pre_starting(), arch_cpu_pre_online() and arch_cpu_post_online().
>> Let me know what you think of those names.
> Much better than "__" - so if none of the guys that excel in core
> code objects go for that.
> 


Ok..

>> Would you kindly add a changelog and your sign-off to this patch?
> Will do in next revision.
> 


Great!

> ...
> 
> Thanks for the throughfull review.
> I will address all points - including passing the pointer down,
> as I assume you have some future plans with that pointer.
> 
>>
>> I still didn't get how this solves the original problem of
>> not having sparc_cpu_model set to sparc_leon. You mentioned
>> that by the time we reach leon_smp_cpu_startup, that variable
>> is not set. Even inside leon_smp_cpu_startup, I don't immediately
>> see where it is set. Am I missing something?
> 
> After looking more closely at the code it is my understanding
> that a leon CPU when started will actually jump to the reset
> vector and start from there.
> So the secondary CPU's will run long time after
> sparc_cpu_model is set so we can safely use it.
> 
> The sun based cpu will in comparsion jump to
> an address supplied to a prom call - so they do not
> jump to the reset vector.
> But they also have sparc_cpu_model set so no problem there
> either.
> 


Ok..

> All this are my deductions from reading the code - but this
> is not an area I have looked at otherwise..
> 
> I may not find time today to cook up a new version of
> the patch - but then you will have it tomorrow.
> 


Sure! Once again, thanks a lot for your time and efforts :-)

Regards,
Srivatsa S. Bhat

--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 291bb5d..2bc1c6d 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -48,6 +48,10 @@  extern void sun4m_init_IRQ(void);
 extern void sun4m_unmask_profile_irq(void);
 extern void sun4m_clear_profile_irq(int cpu);
 
+/* sun4m_smp.c */
+void sun4m_cpu_pre_starting(void);
+void sun4m_cpu_pre_online(void);
+
 /* sun4d_irq.c */
 extern spinlock_t sun4d_imsk_lock;
 
@@ -60,6 +64,14 @@  extern int show_sun4d_interrupts(struct seq_file *, void *);
 extern void sun4d_distribute_irqs(void);
 extern void sun4d_free_irq(unsigned int irq, void *dev_id);
 
+/* sun4d_smp.c */
+void sun4d_cpu_pre_starting(void);
+void sun4d_cpu_pre_online(void);
+
+/* leon_smp.c */
+void leon_cpu_pre_starting(void);
+void leon_cpu_pre_online(void);
+
 /* head_32.S */
 extern unsigned int t_nmi[];
 extern unsigned int linux_trap_ipi15_sun4d[];
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 0f3fb6d..0b028b3 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -69,31 +69,20 @@  static inline unsigned long do_swap(volatile unsigned long *ptr,
 	return val;
 }
 
-void __cpuinit leon_callin(void)
+void __cpuinit leon_cpu_pre_starting(void)
 {
-	int cpuid = hard_smp_processor_id();
-
-	local_ops->cache_all();
-	local_ops->tlb_all();
 	leon_configure_cache_smp();
+}
 
-	notify_cpu_starting(cpuid);
-
-	/* Get our local ticker going. */
-	register_percpu_ce(cpuid);
-
-	calibrate_delay();
-	smp_store_cpu_info(cpuid);
 
-	local_ops->cache_all();
-	local_ops->tlb_all();
+void __cpuinit cpu_cpu_pre_starting(void *unused)
+{
+	int cpuid = hard_smp_processor_id();
 
-	/*
-	 * Unblock the master CPU _only_ when the scheduler state
-	 * of all secondary CPUs will be up-to-date, so after
-	 * the SMP initialization the master will be just allowed
-	 * to call the scheduler code.
-	 * Allow master to continue.
+	/* Allow master to continue. The master will then give us the
+	 * go-ahead by setting the smp_commenced_mask and will wait without
+	 * timeouts until our setup is completed fully (signified by
+	 * our bit being set in the cpu_online_mask).
 	 */
 	do_swap(&cpu_callin_map[cpuid], 1);
 
@@ -110,9 +99,6 @@  void __cpuinit leon_callin(void)
 
 	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
 		mb();
-
-	local_irq_enable();
-	set_cpu_online(cpuid, true);
 }
 
 /*
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index 79db45e..2e2990f 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -20,6 +20,7 @@ 
 #include <linux/seq_file.h>
 #include <linux/cache.h>
 #include <linux/delay.h>
+#include <linux/cpu.h>
 
 #include <asm/ptrace.h>
 #include <linux/atomic.h>
@@ -32,8 +33,10 @@ 
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/cpudata.h>
+#include <asm/timer.h>
 #include <asm/leon.h>
 
+#include "kernel.h"
 #include "irq.h"
 
 volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
@@ -294,6 +297,89 @@  int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
 	return ret;
 }
 
+void __cpuinit __cpu_pre_starting(void *unused)
+{
+	local_ops->cache_all();
+	local_ops->tlb_all();
+
+	switch(sparc_cpu_model) {
+	case sun4m:
+		sun4m_cpu_pre_starting();
+		break;
+	case sun4d:
+		sun4d_cpu_pre_starting();
+		break;
+	case sparc_leon:
+		leon_cpu_pre_starting();
+		break;
+	default:
+		BUG();
+	}
+}
+
+void __cpuinit __cpu_pre_online(void *unused)
+{
+	unsigned int cpuid = hard_smp_processor_id();
+
+	register_percpu_ce(cpuid);
+
+	calibrate_delay();
+	smp_store_cpu_info(cpuid);
+
+	local_ops->cache_all();
+	local_ops->tlb_all();
+
+	switch(sparc_cpu_model) {
+	case sun4m:
+		sun4m_cpu_pre_online();
+		break;
+	case sun4d:
+		sun4d_cpu_pre_online();
+		break;
+	case sparc_leon:
+		leon_cpu_pre_starting();
+		break;
+	default:
+		BUG();
+	}
+}
+
+void __cpuinit sparc_start_secondary(void *unused)
+{
+	unsigned int cpu;
+
+	/*
+	 * SMP booting is extremely fragile in some architectures. So run
+	 * the cpu initialization code first before anything else.
+	 */
+	__cpu_pre_starting(NULL);
+
+	preempt_disable();
+	cpu = smp_processor_id();
+
+	/* Invoke the CPU_STARTING notifier callbacks */
+	notify_cpu_starting(cpu);
+
+	__cpu_pre_online(NULL);
+
+	/* Set the CPU in the cpu_online_mask */
+	set_cpu_online(cpu, true);
+
+	/* Enable local interrupts now */
+	local_irq_enable();
+
+	wmb();
+	cpu_idle();
+
+	/* We should never reach here! */
+	BUG();
+}
+
+void __cpuinit smp_callin(void)
+{
+	sparc_start_secondary(NULL);
+}
+
 void smp_bogo(struct seq_file *m)
 {
 	int i;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index ddaea31..bfbbc46 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -50,10 +50,9 @@  static inline void show_leds(int cpuid)
 			      "i" (ASI_M_CTL));
 }
 
-void __cpuinit smp4d_callin(void)
+void __cpuinit sun4d_cpu_pre_starting(void)
 {
 	int cpuid = hard_smp_processor_id();
-	unsigned long flags;
 
 	/* Show we are alive */
 	cpu_leds[cpuid] = 0x6;
@@ -61,24 +60,14 @@  void __cpuinit smp4d_callin(void)
 
 	/* Enable level15 interrupt, disable level14 interrupt for now */
 	cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
+}
 
-	local_ops->cache_all();
-	local_ops->tlb_all();
-
-	notify_cpu_starting(cpuid);
-	/*
-	 * Unblock the master CPU _only_ when the scheduler state
-	 * of all secondary CPUs will be up-to-date, so after
-	 * the SMP initialization the master will be just allowed
-	 * to call the scheduler code.
-	 */
-	/* Get our local ticker going. */
-	register_percpu_ce(cpuid);
+void __cpuinit sun4d_cpu_pre_online(void)
+{
+	unsigned long flags;
+	int cpuid;
 
-	calibrate_delay();
-	smp_store_cpu_info(cpuid);
-	local_ops->cache_all();
-	local_ops->tlb_all();
+	cpuid = hard_smp_processor_id();
 
 	/* Allow master to continue. */
 	sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
@@ -106,16 +95,12 @@  void __cpuinit smp4d_callin(void)
 	local_ops->cache_all();
 	local_ops->tlb_all();
 
-	local_irq_enable();	/* We don't allow PIL 14 yet */
-
 	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
 		barrier();
 
 	spin_lock_irqsave(&sun4d_imsk_lock, flags);
 	cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
 	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-	set_cpu_online(cpuid, true);
-
 }
 
 /*
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 128af73..0cf6b4f 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -34,30 +34,19 @@  swap_ulong(volatile unsigned long *ptr, unsigned long val)
 	return val;
 }
 
-void __cpuinit smp4m_callin(void)
+void __cpuinit sun4m_cpu_pre_starting(void)
 {
-	int cpuid = hard_smp_processor_id();
-
-	local_ops->cache_all();
-	local_ops->tlb_all();
-
-	notify_cpu_starting(cpuid);
-
-	register_percpu_ce(cpuid);
-
-	calibrate_delay();
-	smp_store_cpu_info(cpuid);
+}
 
-	local_ops->cache_all();
-	local_ops->tlb_all();
+void __cpuinit sun4m_cpu_pre_online(void)
+{
+	int cpuid = hard_smp_processor_id();
 
-	/*
-	 * Unblock the master CPU _only_ when the scheduler state
-	 * of all secondary CPUs will be up-to-date, so after
-	 * the SMP initialization the master will be just allowed
-	 * to call the scheduler code.
+	/* Allow master to continue. The master will then give us the
+	 * go-ahead by setting the smp_commenced_mask and will wait without
+	 * timeouts until our setup is completed fully (signified by
+	 * our bit being set in the cpu_online_mask).
 	 */
-	/* Allow master to continue. */
 	swap_ulong(&cpu_callin_map[cpuid], 1);
 
 	/* XXX: What's up with all the flushes? */
@@ -75,10 +64,6 @@  void __cpuinit smp4m_callin(void)
 
 	while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
 		mb();
-
-	local_irq_enable();
-
-	set_cpu_online(cpuid, true);
 }
 
 /*
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S
index af27aca..6cdb08c 100644
--- a/arch/sparc/kernel/trampoline_32.S
+++ b/arch/sparc/kernel/trampoline_32.S
@@ -79,18 +79,15 @@  cpu3_startup:
 	 nop
 
 	/* Start this processor. */
-	call	smp4m_callin
+	call	smp_callin
 	 nop
 
-	b,a	smp_do_cpu_idle
+	b,a	smp_panic
 
 	.text
 	.align	4
 
-smp_do_cpu_idle:
-	call	cpu_idle
-	 mov	0, %o0
-
+smp_panic:
 	call	cpu_panic
 	 nop
 
@@ -144,10 +141,10 @@  sun4d_cpu_startup:
 	 nop
 
 	/* Start this processor. */
-	call	smp4d_callin
+	call	smp_callin
 	 nop
 
-	b,a	smp_do_cpu_idle
+	b,a	smp_panic
 
 	__CPUINIT
 	.align	4
@@ -201,7 +198,7 @@  leon_smp_cpu_startup:
 	 nop
 
 	/* Start this processor. */
-	call	leon_callin
+	call	smp_callin
 	 nop
 
-	b,a	smp_do_cpu_idle
+	b,a	smp_panic