2006-11-23 00:46:51 +01:00
/*
* PS3 SMP routines .
*
* Copyright ( C ) 2006 Sony Computer Entertainment Inc .
* Copyright 2006 Sony Corp .
*
* 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 ; version 2 of the License .
*
* 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/kernel.h>
# include <linux/smp.h>
# include <asm/machdep.h>
# include <asm/udbg.h>
# include "platform.h"
# if defined(DEBUG)
2007-06-16 07:19:23 +10:00
# define DBG udbg_printf
2006-11-23 00:46:51 +01:00
# else
2007-06-16 07:19:23 +10:00
# define DBG pr_debug
2006-11-23 00:46:51 +01:00
# endif
/**
2007-06-16 07:17:42 +10:00
* ps3_ipi_virqs - a per cpu array of virqs for ipi use
2006-11-23 00:46:51 +01:00
*/
# define MSG_COUNT 4
2009-06-24 15:13:45 +09:00
static DEFINE_PER_CPU ( unsigned int [ MSG_COUNT ] , ps3_ipi_virqs ) ;
2006-11-23 00:46:51 +01:00
2011-05-10 19:29:10 +00:00
static void ps3_smp_message_pass ( int cpu , int msg )
2006-11-23 00:46:51 +01:00
{
int result ;
unsigned int virq ;
if ( msg > = MSG_COUNT ) {
DBG ( " %s:%d: bad msg: %d \n " , __func__ , __LINE__ , msg ) ;
return ;
}
2011-05-10 19:29:10 +00:00
virq = per_cpu ( ps3_ipi_virqs , cpu ) [ msg ] ;
2006-11-23 00:46:51 +01:00
result = ps3_send_event_locally ( virq ) ;
if ( result )
DBG ( " %s:%d: ps3_send_event_locally(%d, %d) failed "
2011-05-10 19:29:10 +00:00
" (%d) \n " , __func__ , __LINE__ , cpu , msg , result ) ;
2006-11-23 00:46:51 +01:00
}
2011-11-29 15:38:50 +00:00
static int __init ps3_smp_probe ( void )
2006-11-23 00:46:51 +01:00
{
2011-11-08 12:38:21 +00:00
int cpu ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
for ( cpu = 0 ; cpu < 2 ; cpu + + ) {
int result ;
unsigned int * virqs = per_cpu ( ps3_ipi_virqs , cpu ) ;
int i ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
DBG ( " -> %s:%d: (%d) \n " , __func__ , __LINE__ , cpu ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
/*
* Check assumptions on ps3_ipi_virqs [ ] indexing . If this
* check fails , then a different mapping of PPC_MSG_
* to index needs to be setup .
*/
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
BUILD_BUG_ON ( PPC_MSG_CALL_FUNCTION ! = 0 ) ;
BUILD_BUG_ON ( PPC_MSG_RESCHEDULE ! = 1 ) ;
BUILD_BUG_ON ( PPC_MSG_CALL_FUNC_SINGLE ! = 2 ) ;
BUILD_BUG_ON ( PPC_MSG_DEBUGGER_BREAK ! = 3 ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
for ( i = 0 ; i < MSG_COUNT ; i + + ) {
result = ps3_event_receive_port_setup ( cpu , & virqs [ i ] ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
if ( result )
continue ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
DBG ( " %s:%d: (%d, %d) => virq %u \n " ,
__func__ , __LINE__ , cpu , i , virqs [ i ] ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
result = smp_request_message_ipi ( virqs [ i ] , i ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
if ( result )
virqs [ i ] = NO_IRQ ;
else
ps3_register_ipi_irq ( cpu , virqs [ i ] ) ;
}
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
ps3_register_ipi_debug_brk ( cpu , virqs [ PPC_MSG_DEBUGGER_BREAK ] ) ;
2006-11-23 00:46:51 +01:00
2011-11-08 12:38:21 +00:00
DBG ( " <- %s:%d: (%d) \n " , __func__ , __LINE__ , cpu ) ;
}
return 2 ;
2006-11-23 00:46:51 +01:00
}
void ps3_smp_cleanup_cpu ( int cpu )
{
2007-06-16 07:17:42 +10:00
unsigned int * virqs = per_cpu ( ps3_ipi_virqs , cpu ) ;
2006-11-23 00:46:51 +01:00
int i ;
DBG ( " -> %s:%d: (%d) \n " , __func__ , __LINE__ , cpu ) ;
2007-05-01 07:01:01 +10:00
2006-11-23 00:46:51 +01:00
for ( i = 0 ; i < MSG_COUNT ; i + + ) {
2007-06-16 07:19:32 +10:00
/* Can't call free_irq from interrupt context. */
2007-05-01 07:01:01 +10:00
ps3_event_receive_port_destroy ( virqs [ i ] ) ;
2006-11-23 00:46:51 +01:00
virqs [ i ] = NO_IRQ ;
}
2007-05-01 07:01:01 +10:00
2006-11-23 00:46:51 +01:00
DBG ( " <- %s:%d: (%d) \n " , __func__ , __LINE__ , cpu ) ;
}
static struct smp_ops_t ps3_smp_ops = {
. probe = ps3_smp_probe ,
. message_pass = ps3_smp_message_pass ,
. kick_cpu = smp_generic_kick_cpu ,
} ;
void smp_init_ps3 ( void )
{
DBG ( " -> %s \n " , __func__ ) ;
smp_ops = & ps3_smp_ops ;
DBG ( " <- %s \n " , __func__ ) ;
}