Blackfin: SMP: don't start up core b until its state has been completely onlined

When testing PREEMPT_RT kernel on BF561-EZKit, the kernel blocks while
booting.  When the kernel initializes the ethernet driver, it sleeps and
never wakes up.

The issue happens when the kernel waits for a timer for Core B to timeout
(the timers are per-cpu based: static DEFINE_PER_CPU(struct tvec_base *,
tvec_bases) = &boot_tvec_bases).

However, the ksoftirqd thread for Core B (note, the ksoftirqd thread is
also per-cpu based) cannot work properly, and the timers for Core B never
times out.

When ksoftirqd() for the first time runs on core B, it is possible core A
is still initializing core B (see smp_init() -> cpu_up() -> __cpu_up()).
So the "cpu_is_offline()" check may return true and ksoftirqd moves to
"wait_to_die".

So delay the core b start up until the per-cpu timers have been set up
fully.

Signed-off-by: Yi Li <yi.li@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 510f576..0192532 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -52,8 +52,6 @@
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
-	local_irq_disable();
-
 	/* Clone setup for peripheral interrupt sources from CoreA. */
 	bfin_write_SICB_IMASK0(bfin_read_SICA_IMASK0());
 	bfin_write_SICB_IMASK1(bfin_read_SICA_IMASK1());
@@ -70,11 +68,6 @@
 	bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
 	SSYNC();
 
-	local_irq_enable();
-
-	/* Calibrate loops per jiffy value. */
-	calibrate_delay();
-
 	/* Store CPU-private information to the cpu_data array. */
 	bfin_setup_cpudata(cpu);
 
@@ -108,9 +101,13 @@
 		barrier();
 	}
 
-	spin_unlock(&boot_lock);
-
-	return cpu_isset(cpu, cpu_callin_map) ? 0 : -ENOSYS;
+	if (cpu_isset(cpu, cpu_callin_map)) {
+		cpu_set(cpu, cpu_online_map);
+		/* release the lock and let coreb run */
+		spin_unlock(&boot_lock);
+		return 0;
+	} else
+		panic("CPU%u: processor failed to boot\n", cpu);
 }
 
 void __init platform_request_ipi(irq_handler_t handler)
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index d92b168..369e687 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -336,13 +336,6 @@
 
 	ret = platform_boot_secondary(cpu, idle);
 
-	if (ret) {
-		cpu_clear(cpu, cpu_present_map);
-		printk(KERN_CRIT "CPU%u: processor failed to boot (%d)\n", cpu, ret);
-		free_task(idle);
-	} else
-		cpu_set(cpu, cpu_online_map);
-
 	secondary_stack = NULL;
 
 	return ret;
@@ -418,9 +411,16 @@
 
 	setup_secondary(cpu);
 
+	platform_secondary_init(cpu);
+
 	local_irq_enable();
 
-	platform_secondary_init(cpu);
+	/*
+	 * Calibrate loops per jiffy value.
+	 * IRQs need to be enabled here - D-cache can be invalidated
+	 * in timer irq handler, so core B can read correct jiffies.
+	 */
+	calibrate_delay();
 
 	cpu_idle();
 }