2010-02-12 00:56:07 +03:00
/*
* linux / arch / arm / mach - vexpress / platsmp . c
*
* Copyright ( C ) 2002 ARM Ltd .
* All Rights Reserved
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/smp.h>
# include <linux/io.h>
# include <asm/unified.h>
# include <mach/motherboard.h>
# define V2M_PA_CS7 0x10000000
# include "core.h"
2011-01-19 13:24:56 +03:00
extern void versatile_secondary_startup ( void ) ;
ARM: Fix subtle race in CPU pen_release hotplug code
There is a subtle race in the CPU hotplug code, where a CPU which has
been offlined can online itself before being requested, which results
in things going astray on the next online/offline cycle.
What happens in the normal online/offline/online cycle is:
CPU0 CPU3
requests boot of CPU3
pen_release = 3
flush cache line
checks pen_release, reads 3
starts boot
pen_release = -1
... requests CPU3 offline ...
... dies ...
checks pen_release, reads -1
requests boot of CPU3
pen_release = 3
flush cache line
checks pen_release, reads 3
starts boot
pen_release = -1
However, as the write of -1 of pen_release is not fully flushed back to
memory, and the checking of pen_release is done with caches disabled,
this allows CPU3 the opportunity to read the old value of pen_release:
CPU0 CPU3
requests boot of CPU3
pen_release = 3
flush cache line
checks pen_release, reads 3
starts boot
pen_release = -1
... requests CPU3 offline ...
... dies ...
checks pen_release, reads 3
starts boot
pen_release = -1
requests boot of CPU3
pen_release = 3
flush cache line
Fix this by grouping the write of pen_release along with its cache line
flushing code to ensure that any update to pen_release is always pushed
out to physical memory.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2010-12-18 13:53:12 +03:00
2010-02-12 00:56:07 +03:00
/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system .
*/
void __init smp_init_cpus ( void )
{
2011-02-28 19:01:04 +03:00
ct_desc - > init_cpu_map ( ) ;
2010-02-12 00:56:07 +03:00
}
2010-12-03 14:09:48 +03:00
void __init platform_smp_prepare_cpus ( unsigned int max_cpus )
2010-02-12 00:56:07 +03:00
{
/*
* Initialise the present map , which describes the set of CPUs
* actually populated at the present time .
*/
2011-02-28 19:01:04 +03:00
ct_desc - > smp_enable ( max_cpus ) ;
2010-12-03 14:09:48 +03:00
2010-02-12 00:56:07 +03:00
/*
2010-12-03 14:09:48 +03:00
* Write the address of secondary startup into the
* system - wide flags register . The boot monitor waits
* until it receives a soft interrupt , and then the
* secondary CPU branches to this address .
2010-02-12 00:56:07 +03:00
*/
2010-12-03 14:09:48 +03:00
writel ( ~ 0 , MMIO_P2V ( V2M_SYS_FLAGSCLR ) ) ;
2011-01-19 13:24:56 +03:00
writel ( BSYM ( virt_to_phys ( versatile_secondary_startup ) ) ,
2010-12-03 14:09:48 +03:00
MMIO_P2V ( V2M_SYS_FLAGSSET ) ) ;
2010-02-12 00:56:07 +03:00
}