2006-06-17 17:52:45 -05:00
/*
* Author : Xianghua Xiao < x . xiao @ freescale . com >
* Zhang Wei < wei . zhang @ freescale . com >
*
* Copyright 2006 Freescale Semiconductor Inc .
*
* 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 .
*/
# include <linux/stddef.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/delay.h>
2008-06-24 11:32:21 +10:00
# include <asm/code-patching.h>
2006-06-17 17:52:45 -05:00
# include <asm/page.h>
2007-05-09 15:20:37 +10:00
# include <asm/pgtable.h>
2006-06-17 17:52:45 -05:00
# include <asm/pci-bridge.h>
2008-08-01 15:20:30 +10:00
# include <asm/mpic.h>
2006-06-17 17:52:45 -05:00
# include <asm/cacheflush.h>
# include <sysdev/fsl_soc.h>
# include "mpc86xx.h"
extern void __secondary_start_mpc86xx ( void ) ;
2009-04-22 12:32:09 -05:00
# define MCM_PORT_CONFIG_OFFSET 0x10
/* Offset from CCSRBAR */
# define MPC86xx_MCM_OFFSET (0x1000)
# define MPC86xx_MCM_SIZE (0x1000)
2006-06-17 17:52:45 -05:00
static void __init
smp_86xx_release_core ( int nr )
{
2006-06-28 00:37:45 -05:00
__be32 __iomem * mcm_vaddr ;
unsigned long pcr ;
2006-06-17 17:52:45 -05:00
if ( nr < 0 | | nr > = NR_CPUS )
return ;
/*
* Startup Core # nr .
*/
mcm_vaddr = ioremap ( get_immrbase ( ) + MPC86xx_MCM_OFFSET ,
MPC86xx_MCM_SIZE ) ;
2006-06-28 00:37:45 -05:00
pcr = in_be32 ( mcm_vaddr + ( MCM_PORT_CONFIG_OFFSET > > 2 ) ) ;
2006-06-17 17:52:45 -05:00
pcr | = 1 < < ( nr + 24 ) ;
2006-06-28 00:37:45 -05:00
out_be32 ( mcm_vaddr + ( MCM_PORT_CONFIG_OFFSET > > 2 ) , pcr ) ;
2009-04-22 12:32:09 -05:00
iounmap ( mcm_vaddr ) ;
2006-06-17 17:52:45 -05:00
}
2011-04-11 21:46:19 +00:00
static int __init
2006-06-17 17:52:45 -05:00
smp_86xx_kick_cpu ( int nr )
{
unsigned int save_vector ;
unsigned long target , flags ;
int n = 0 ;
2008-06-24 11:32:22 +10:00
unsigned int * vector = ( unsigned int * ) ( KERNELBASE + 0x100 ) ;
2006-06-17 17:52:45 -05:00
if ( nr < 0 | | nr > = NR_CPUS )
2011-04-11 21:46:19 +00:00
return - ENOENT ;
2006-06-17 17:52:45 -05:00
pr_debug ( " smp_86xx_kick_cpu: kick CPU #%d \n " , nr ) ;
local_irq_save ( flags ) ;
/* Save reset vector */
save_vector = * vector ;
/* Setup fake reset vector to call __secondary_start_mpc86xx. */
target = ( unsigned long ) __secondary_start_mpc86xx ;
2008-06-24 11:32:22 +10:00
patch_branch ( vector , target , BRANCH_SET_LINK ) ;
2006-06-17 17:52:45 -05:00
/* Kick that CPU */
smp_86xx_release_core ( nr ) ;
/* Wait a bit for the CPU to take the exception. */
while ( ( __secondary_hold_acknowledge ! = nr ) & & ( n + + , n < 1000 ) )
mdelay ( 1 ) ;
/* Restore the exception vector */
* vector = save_vector ;
flush_icache_range ( ( unsigned long ) vector , ( unsigned long ) vector + 4 ) ;
local_irq_restore ( flags ) ;
pr_debug ( " wait CPU #%d for %d msecs. \n " , nr , n ) ;
2011-04-11 21:46:19 +00:00
return 0 ;
2006-06-17 17:52:45 -05:00
}
static void __init
smp_86xx_setup_cpu ( int cpu_nr )
{
mpic_setup_this_cpu ( ) ;
}
struct smp_ops_t smp_86xx_ops = {
. message_pass = smp_mpic_message_pass ,
. probe = smp_mpic_probe ,
. kick_cpu = smp_86xx_kick_cpu ,
. setup_cpu = smp_86xx_setup_cpu ,
. take_timebase = smp_generic_take_timebase ,
. give_timebase = smp_generic_give_timebase ,
} ;
void __init
mpc86xx_smp_init ( void )
{
smp_ops = & smp_86xx_ops ;
}