2005-04-17 02:20:36 +04:00
/*
* SMP support for iSeries machines .
*
* Dave Engebretsen , Peter Bergner , and
* Mike Corrigan { engebret | bergner | mikec } @ us . ibm . com
*
* Plus various changes from other IBM teams . . .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# undef DEBUG
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/smp.h>
# include <linux/interrupt.h>
# include <linux/kernel_stat.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/spinlock.h>
# include <linux/cache.h>
# include <linux/err.h>
# include <linux/sysdev.h>
# include <linux/cpu.h>
# include <asm/ptrace.h>
# include <asm/atomic.h>
# include <asm/irq.h>
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/io.h>
# include <asm/smp.h>
# include <asm/paca.h>
2005-11-01 08:59:20 +03:00
# include <asm/iseries/hv_call.h>
2005-04-17 02:20:36 +04:00
# include <asm/time.h>
# include <asm/machdep.h>
# include <asm/cputable.h>
# include <asm/system.h>
2006-10-06 07:55:26 +04:00
# include "smp.h"
2005-04-17 02:20:36 +04:00
static unsigned long iSeries_smp_message [ NR_CPUS ] ;
2006-10-06 07:55:26 +04:00
void iSeries_smp_message_recv ( void )
2005-04-17 02:20:36 +04:00
{
int cpu = smp_processor_id ( ) ;
int msg ;
2005-09-27 21:07:14 +04:00
if ( num_online_cpus ( ) < 2 )
2005-04-17 02:20:36 +04:00
return ;
2005-09-27 21:07:14 +04:00
for ( msg = 0 ; msg < 4 ; msg + + )
if ( test_and_clear_bit ( msg , & iSeries_smp_message [ cpu ] ) )
2006-10-06 07:55:26 +04:00
smp_message_recv ( msg ) ;
2005-04-17 02:20:36 +04:00
}
static inline void smp_iSeries_do_message ( int cpu , int msg )
{
set_bit ( msg , & iSeries_smp_message [ cpu ] ) ;
HvCall_sendIPI ( & ( paca [ cpu ] ) ) ;
}
static void smp_iSeries_message_pass ( int target , int msg )
{
int i ;
if ( target < NR_CPUS )
smp_iSeries_do_message ( target , msg ) ;
else {
for_each_online_cpu ( i ) {
2005-09-27 21:07:14 +04:00
if ( ( target = = MSG_ALL_BUT_SELF ) & &
( i = = smp_processor_id ( ) ) )
2005-04-17 02:20:36 +04:00
continue ;
smp_iSeries_do_message ( i , msg ) ;
}
}
}
static int smp_iSeries_probe ( void )
{
2005-09-23 09:03:10 +04:00
return cpus_weight ( cpu_possible_map ) ;
2005-04-17 02:20:36 +04:00
}
static void smp_iSeries_kick_cpu ( int nr )
{
2005-09-27 21:07:14 +04:00
BUG_ON ( ( nr < 0 ) | | ( nr > = NR_CPUS ) ) ;
2005-04-17 02:20:36 +04:00
/* Verify that our partition has a processor nr */
2006-01-13 02:26:42 +03:00
if ( lppaca [ nr ] . dyn_proc_status > = 2 )
2005-04-17 02:20:36 +04:00
return ;
/* The processor is currently spinning, waiting
* for the cpu_start field to become non - zero
* After we set cpu_start , the processor will
* continue on to secondary_start in iSeries_head . S
*/
paca [ nr ] . cpu_start = 1 ;
}
static void __devinit smp_iSeries_setup_cpu ( int nr )
{
}
static struct smp_ops_t iSeries_smp_ops = {
. message_pass = smp_iSeries_message_pass ,
. probe = smp_iSeries_probe ,
. kick_cpu = smp_iSeries_kick_cpu ,
. setup_cpu = smp_iSeries_setup_cpu ,
} ;
/* This is called very early. */
void __init smp_init_iSeries ( void )
{
smp_ops = & iSeries_smp_ops ;
}