2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 2001 , 2002 , 2003 Broadcom Corporation
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/smp.h>
# include <linux/kernel_stat.h>
# include <asm/mmu_context.h>
# include <asm/io.h>
2007-11-19 12:23:51 +00:00
# include <asm/fw/cfe/cfe_api.h>
2005-04-16 15:20:36 -07:00
# include <asm/sibyte/sb1250.h>
# include <asm/sibyte/sb1250_regs.h>
# include <asm/sibyte/sb1250_int.h>
static void * mailbox_set_regs [ ] = {
2005-02-22 21:51:30 +00:00
IOADDR ( A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU ) ,
IOADDR ( A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU )
2005-04-16 15:20:36 -07:00
} ;
static void * mailbox_clear_regs [ ] = {
2005-02-22 21:51:30 +00:00
IOADDR ( A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU ) ,
IOADDR ( A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU )
2005-04-16 15:20:36 -07:00
} ;
static void * mailbox_regs [ ] = {
2005-02-22 21:51:30 +00:00
IOADDR ( A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU ) ,
IOADDR ( A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU )
2005-04-16 15:20:36 -07:00
} ;
/*
* SMP init and finish on secondary CPUs
*/
2007-10-22 10:38:44 +01:00
void __cpuinit sb1250_smp_init ( void )
2005-04-16 15:20:36 -07:00
{
unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
STATUSF_IP1 | STATUSF_IP0 ;
/* Set interrupt mask, but don't enable */
change_c0_status ( ST0_IM , imask ) ;
}
2007-11-19 12:23:51 +00:00
/*
* These are routines for dealing with the sb1250 smp capabilities
* independent of board / firmware
*/
/*
* Simple enough ; everything is set up , so just poke the appropriate mailbox
* register , and we should be set
*/
static void sb1250_send_ipi_single ( int cpu , unsigned int action )
{
__raw_writeq ( ( ( ( u64 ) action ) < < 48 ) , mailbox_set_regs [ cpu ] ) ;
}
static inline void sb1250_send_ipi_mask ( cpumask_t mask , unsigned int action )
{
unsigned int i ;
for_each_cpu_mask ( i , mask )
sb1250_send_ipi_single ( i , action ) ;
}
/*
* Code to run on secondary just after probing the CPU
*/
static void __cpuinit sb1250_init_secondary ( void )
{
extern void sb1250_smp_init ( void ) ;
sb1250_smp_init ( ) ;
}
/*
* Do any tidying up before marking online and running the idle
* loop
*/
static void __cpuinit sb1250_smp_finish ( void )
2005-04-16 15:20:36 -07:00
{
2007-10-19 08:22:38 +01:00
extern void sb1250_clockevent_init ( void ) ;
sb1250_clockevent_init ( ) ;
2005-04-16 15:20:36 -07:00
local_irq_enable ( ) ;
}
/*
2007-11-19 12:23:51 +00:00
* Final cleanup after all secondaries booted
2005-04-16 15:20:36 -07:00
*/
2007-11-19 12:23:51 +00:00
static void sb1250_cpus_done ( void )
{
}
2005-04-16 15:20:36 -07:00
/*
2007-11-19 12:23:51 +00:00
* Setup the PC , SP , and GP of a secondary processor and start it
* running !
2005-04-16 15:20:36 -07:00
*/
2007-11-19 12:23:51 +00:00
static void __cpuinit sb1250_boot_secondary ( int cpu , struct task_struct * idle )
2005-04-16 15:20:36 -07:00
{
2007-11-19 12:23:51 +00:00
int retval ;
retval = cfe_cpu_start ( cpu_logical_map ( cpu ) , & smp_bootstrap ,
__KSTK_TOS ( idle ) ,
( unsigned long ) task_thread_info ( idle ) , 0 ) ;
if ( retval ! = 0 )
printk ( " cfe_start_cpu(%i) returned %i \n " , cpu , retval ) ;
2005-04-16 15:20:36 -07:00
}
2007-11-19 12:23:51 +00:00
/*
* Use CFE to find out how many CPUs are available , setting up
* phys_cpu_present_map and the logical / physical mappings .
* XXXKW will the boot CPU ever not be physical 0 ?
*
* Common setup before any secondaries are started
*/
static void __init sb1250_smp_setup ( void )
{
int i , num ;
cpus_clear ( phys_cpu_present_map ) ;
cpu_set ( 0 , phys_cpu_present_map ) ;
__cpu_number_map [ 0 ] = 0 ;
__cpu_logical_map [ 0 ] = 0 ;
for ( i = 1 , num = 0 ; i < NR_CPUS ; i + + ) {
if ( cfe_cpu_stop ( i ) = = 0 ) {
cpu_set ( i , phys_cpu_present_map ) ;
__cpu_number_map [ i ] = + + num ;
__cpu_logical_map [ num ] = i ;
}
}
printk ( KERN_INFO " Detected %i available secondary CPU(s) \n " , num ) ;
}
static void __init sb1250_prepare_cpus ( unsigned int max_cpus )
{
}
struct plat_smp_ops sb_smp_ops = {
. send_ipi_single = sb1250_send_ipi_single ,
. send_ipi_mask = sb1250_send_ipi_mask ,
. init_secondary = sb1250_init_secondary ,
. smp_finish = sb1250_smp_finish ,
. cpus_done = sb1250_cpus_done ,
. boot_secondary = sb1250_boot_secondary ,
. smp_setup = sb1250_smp_setup ,
. prepare_cpus = sb1250_prepare_cpus ,
} ;
2006-10-07 19:44:33 +01:00
void sb1250_mailbox_interrupt ( void )
2005-04-16 15:20:36 -07:00
{
int cpu = smp_processor_id ( ) ;
unsigned int action ;
kstat_this_cpu . irqs [ K_INT_MBOX_0 ] + + ;
/* Load the mailbox register to figure out what we're supposed to do */
2005-02-22 21:51:30 +00:00
action = ( ____raw_readq ( mailbox_regs [ cpu ] ) > > 48 ) & 0xffff ;
2005-04-16 15:20:36 -07:00
/* Clear the mailbox to clear the interrupt */
2005-02-22 21:51:30 +00:00
____raw_writeq ( ( ( u64 ) action ) < < 48 , mailbox_clear_regs [ cpu ] ) ;
2005-04-16 15:20:36 -07:00
/*
* Nothing to do for SMP_RESCHEDULE_YOURSELF ; returning from the
* interrupt will do the reschedule for us
*/
if ( action & SMP_CALL_FUNCTION )
smp_call_function_interrupt ( ) ;
}