mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
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>
This commit is contained in:
parent
ad774b7cb0
commit
578d36f5e1
2 changed files with 15 additions and 18 deletions
|
@ -52,8 +52,6 @@ int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
|
|||
|
||||
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 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
|
|||
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 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
|
|||
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)
|
||||
|
|
|
@ -336,13 +336,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
|
|||
|
||||
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 @@ void __cpuinit secondary_start_kernel(void)
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue