sparc32: refactor smp boot
authorSam Ravnborg <sam@ravnborg.org>
Fri, 15 Feb 2013 14:52:06 +0000 (15:52 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Feb 2013 21:36:50 +0000 (13:36 -0800)
Introduce a common smp_callin() function to call
from trampoline_32.S.
Add platform specific functions to handle the
platform details.

This is in preparation for a patch that will
unify the smp boot stuff for all architectures.
sparc32 was significantly different to warrant
this patch in preparation.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Acked-by: David S. Miller <davem@davemloft.net>
Cc: "Srivatsa S. Bhat" <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/kernel.h
arch/sparc/kernel/leon_smp.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/trampoline_32.S

index 291bb5de9ce0963184518a9a00872370821075d1..a702d9ab019c23e13bfdaa681ebf40f625adb6c1 100644 (file)
@@ -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 *arg);
+void sun4m_cpu_pre_online(void *arg);
+
 /* 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 *arg);
+void sun4d_cpu_pre_online(void *arg);
+
+/* leon_smp.c */
+void leon_cpu_pre_starting(void *arg);
+void leon_cpu_pre_online(void *arg);
+
 /* head_32.S */
 extern unsigned int t_nmi[];
 extern unsigned int linux_trap_ipi15_sun4d[];
index 0f3fb6d9c8efc3e8cd0f12e48d3ff26d87a6699f..9b40c9c12a0c986534a722858a2219bb8f87614a 100644 (file)
@@ -69,31 +69,19 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
        return val;
 }
 
-void __cpuinit leon_callin(void)
+void __cpuinit leon_cpu_pre_starting(void *arg)
 {
-       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 leon_cpu_pre_online(void *arg)
+{
+       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 +98,6 @@ void __cpuinit leon_callin(void)
 
        while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
                mb();
-
-       local_irq_enable();
-       set_cpu_online(cpuid, true);
 }
 
 /*
index 79db45e5134a6df24de2805a597cc35c3b3cc347..9e7e6d718367b18ddc2fe1c354e7509c6c524384 100644 (file)
@@ -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>
 #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 arch_cpu_pre_starting(void *arg)
+{
+       local_ops->cache_all();
+       local_ops->tlb_all();
+
+       switch(sparc_cpu_model) {
+       case sun4m:
+               sun4m_cpu_pre_starting(arg);
+               break;
+       case sun4d:
+               sun4d_cpu_pre_starting(arg);
+               break;
+       case sparc_leon:
+               leon_cpu_pre_starting(arg);
+               break;
+       default:
+               BUG();
+       }
+}
+
+void __cpuinit arch_cpu_pre_online(void *arg)
+{
+       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(arg);
+               break;
+       case sun4d:
+               sun4d_cpu_pre_online(arg);
+               break;
+       case sparc_leon:
+               leon_cpu_pre_online(arg);
+               break;
+       default:
+               BUG();
+       }
+}
+
+void __cpuinit sparc_start_secondary(void *arg)
+{
+       unsigned int cpu;
+
+       /*
+        * SMP booting is extremely fragile in some architectures. So run
+        * the cpu initialization code first before anything else.
+        */
+       arch_cpu_pre_starting(arg);
+
+       preempt_disable();
+       cpu = smp_processor_id();
+
+       /* Invoke the CPU_STARTING notifier callbacks */
+       notify_cpu_starting(cpu);
+
+       arch_cpu_pre_online(arg);
+
+       /* 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;
index ddaea31de586d47e72c013a565000bdec6a9645f..c9eb82f23d92843a7878bac4b60f7cd766b54420 100644 (file)
@@ -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 *arg)
 {
        int cpuid = hard_smp_processor_id();
-       unsigned long flags;
 
        /* Show we are alive */
        cpu_leds[cpuid] = 0x6;
@@ -61,26 +60,20 @@ 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();
+void __cpuinit sun4d_cpu_pre_online(void *arg)
+{
+       unsigned long flags;
+       int cpuid;
 
-       notify_cpu_starting(cpuid);
-       /*
-        * Unblock the master CPU _only_ when the scheduler state
+       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.
         */
-       /* Get our local ticker going. */
-       register_percpu_ce(cpuid);
-
-       calibrate_delay();
-       smp_store_cpu_info(cpuid);
-       local_ops->cache_all();
-       local_ops->tlb_all();
-
-       /* Allow master to continue. */
        sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
        local_ops->cache_all();
        local_ops->tlb_all();
@@ -106,16 +99,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);
-
 }
 
 /*
index 128af73042881a21e0014bb4db30af741626c824..8a65f158153ddcc26deb2cb820e6387d775cd079 100644 (file)
@@ -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 *arg)
 {
-       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 *arg)
+{
+       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);
 }
 
 /*
index af27acab44868a085ad2182049d81a6da61831e2..6cdb08cdabf092459d209f3a1f2f52ede68fb8d1 100644 (file)
@@ -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