2005-06-19 12:52:07 +04:00
/*
* linux / arch / arm / mach - cintegrator / 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/kernel.h>
# include <linux/sched.h>
# include <linux/errno.h>
# include <linux/mm.h>
# include <asm/atomic.h>
2005-07-29 19:36:48 +04:00
# include <asm/cacheflush.h>
2005-06-19 12:52:07 +04:00
# include <asm/delay.h>
# include <asm/mmu_context.h>
# include <asm/procinfo.h>
# include <asm/ptrace.h>
# include <asm/smp.h>
extern void integrator_secondary_startup ( void ) ;
/*
* control for which core is the next to come out of the secondary
* boot " holding pen "
*/
2005-07-21 00:32:26 +04:00
volatile int __cpuinitdata pen_release = - 1 ;
unsigned long __cpuinitdata phys_pen_release = 0 ;
2005-06-19 12:52:07 +04:00
static DEFINE_SPINLOCK ( boot_lock ) ;
2005-07-18 00:35:41 +04:00
void __cpuinit platform_secondary_init ( unsigned int cpu )
2005-06-19 12:52:07 +04:00
{
/*
* the primary core may have used a " cross call " soft interrupt
* to get this processor out of WFI in the BootMonitor - make
* sure that we are no longer being sent this soft interrupt
*/
smp_cross_call_done ( cpumask_of_cpu ( cpu ) ) ;
/*
* if any interrupts are already enabled for the primary
* core ( e . g . timer irq ) , then they will not have been enabled
* for us : do so
*/
secondary_scan_irqs ( ) ;
/*
* let the primary processor know we ' re out of the
* pen , then head off into the C entry point
*/
pen_release = - 1 ;
/*
* Synchronise with the boot thread .
*/
spin_lock ( & boot_lock ) ;
spin_unlock ( & boot_lock ) ;
}
2005-07-18 00:35:41 +04:00
int __cpuinit boot_secondary ( unsigned int cpu , struct task_struct * idle )
2005-06-19 12:52:07 +04:00
{
unsigned long timeout ;
/*
* set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock ( & boot_lock ) ;
/*
* The secondary processor is waiting to be released from
* the holding pen - release it , then wait for it to flag
* that it has been released by resetting pen_release .
*
* Note that " pen_release " is the hardware CPU ID , whereas
* " cpu " is Linux ' s internal ID .
*/
pen_release = cpu ;
2005-07-29 19:36:48 +04:00
flush_cache_all ( ) ;
2005-06-19 12:52:07 +04:00
/*
* XXX
*
* This is a later addition to the booting protocol : the
* bootMonitor now puts secondary cores into WFI , so
* poke_milo ( ) no longer gets the cores moving ; we need
* to send a soft interrupt to wake the secondary core .
* Use smp_cross_call ( ) for this , since there ' s little
* point duplicating the code here
*/
smp_cross_call ( cpumask_of_cpu ( cpu ) ) ;
timeout = jiffies + ( 1 * HZ ) ;
while ( time_before ( jiffies , timeout ) ) {
if ( pen_release = = - 1 )
break ;
udelay ( 10 ) ;
}
/*
* now the secondary core is starting up let it run its
* calibrations , then wait for it to finish
*/
spin_unlock ( & boot_lock ) ;
return pen_release ! = - 1 ? - ENOSYS : 0 ;
}
static void __init poke_milo ( void )
{
extern void secondary_startup ( void ) ;
/* nobody is to be released from the pen yet */
pen_release = - 1 ;
phys_pen_release = virt_to_phys ( & pen_release ) ;
/*
* write the address of secondary startup into the system - wide
* flags register , then clear the bottom two bits , which is what
* BootMonitor is waiting for
*/
# if 1
# define CINTEGRATOR_HDR_FLAGSS_OFFSET 0x30
__raw_writel ( virt_to_phys ( integrator_secondary_startup ) ,
( IO_ADDRESS ( INTEGRATOR_HDR_BASE ) +
CINTEGRATOR_HDR_FLAGSS_OFFSET ) ) ;
# define CINTEGRATOR_HDR_FLAGSC_OFFSET 0x34
__raw_writel ( 3 ,
( IO_ADDRESS ( INTEGRATOR_HDR_BASE ) +
CINTEGRATOR_HDR_FLAGSC_OFFSET ) ) ;
# endif
mb ( ) ;
}
void __init smp_prepare_cpus ( unsigned int max_cpus )
{
unsigned int ncores = get_core_count ( ) ;
unsigned int cpu = smp_processor_id ( ) ;
int i ;
/* sanity check */
if ( ncores = = 0 ) {
printk ( KERN_ERR
" Integrator/CP: strange CM count of 0? Default to 1 \n " ) ;
ncores = 1 ;
}
if ( ncores > NR_CPUS ) {
printk ( KERN_WARNING
" Integrator/CP: no. of cores (%d) greater than configured "
" maximum of %d - clipping \n " ,
ncores , NR_CPUS ) ;
ncores = NR_CPUS ;
}
/*
* start with some more config for the Boot CPU , now that
* the world is a bit more alive ( which was not the case
* when smp_prepare_boot_cpu ( ) was called )
*/
smp_store_cpu_info ( cpu ) ;
/*
* are we trying to boot more cores than exist ?
*/
if ( max_cpus > ncores )
max_cpus = ncores ;
/*
2005-07-11 22:42:58 +04:00
* Initialise the possible / present maps .
* cpu_possible_map describes the set of CPUs which may be present
* cpu_present_map describes the set of CPUs populated
2005-06-19 12:52:07 +04:00
*/
for ( i = 0 ; i < max_cpus ; i + + ) {
2005-07-11 20:38:36 +04:00
cpu_set ( i , cpu_possible_map ) ;
2005-07-11 22:42:58 +04:00
cpu_set ( i , cpu_present_map ) ;
2005-06-19 12:52:07 +04:00
}
/*
* Do we need any more CPUs ? If so , then let them know where
* to start . Note that , on modern versions of MILO , the " poke "
* doesn ' t actually do anything until each individual core is
* sent a soft interrupt to get it out of WFI
*/
if ( max_cpus > 1 )
poke_milo ( ) ;
}