2008-04-28 17:14:26 +01:00
/*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope 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 .
*
* Copyright ( C ) 2007 MIPS Technologies , Inc .
* Chris Dearman ( chris @ mips . com )
*/
# undef DEBUG
# include <linux/kernel.h>
# include <linux/sched.h>
2009-06-19 14:05:26 +01:00
# include <linux/smp.h>
2008-04-28 17:14:26 +01:00
# include <linux/cpumask.h>
# include <linux/interrupt.h>
# include <linux/compiler.h>
2014-10-20 12:03:53 -07:00
# include <linux/irqchip/mips-gic.h>
2008-04-28 17:14:26 +01:00
2011-07-26 16:09:06 -07:00
# include <linux/atomic.h>
2008-04-28 17:14:26 +01:00
# include <asm/cacheflush.h>
# include <asm/cpu.h>
# include <asm/processor.h>
# include <asm/hardirq.h>
# include <asm/mmu_context.h>
# include <asm/smp.h>
# include <asm/time.h>
# include <asm/mipsregs.h>
# include <asm/mipsmtregs.h>
# include <asm/mips_mt.h>
2009-06-17 16:22:53 -07:00
# include <asm/amon.h>
2008-04-28 17:14:26 +01:00
static void cmp_init_secondary ( void )
{
2014-03-24 10:19:28 +00:00
struct cpuinfo_mips * c __maybe_unused = & current_cpu_data ;
2008-04-28 17:14:26 +01:00
/* Assume GIC is present */
2015-01-16 11:10:46 +00:00
change_c0_status ( ST0_IM , STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 |
STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7 ) ;
2008-04-28 17:14:26 +01:00
/* Enable per-cpu interrupts: platform specific */
2014-05-23 16:29:44 +02:00
# ifdef CONFIG_MIPS_MT_SMP
2013-09-11 14:17:47 -05:00
if ( cpu_has_mipsmt )
c - > vpe_id = ( read_c0_tcbind ( ) > > TCBIND_CURVPE_SHIFT ) &
TCBIND_CURVPE ;
2008-04-28 17:14:26 +01:00
# endif
}
static void cmp_smp_finish ( void )
{
pr_debug ( " SMPCMP: CPU%d: %s \n " , smp_processor_id ( ) , __func__ ) ;
/* CDFIXME: remove this? */
write_c0_compare ( read_c0_count ( ) + ( 8 * mips_hpt_frequency / HZ ) ) ;
# ifdef CONFIG_MIPS_MT_FPAFF
/* If we have an FPU, enroll ourselves in the FPU-full mask */
if ( cpu_has_fpu )
2015-03-05 10:49:17 +10:30
cpumask_set_cpu ( smp_processor_id ( ) , & mt_fpu_cpumask ) ;
2008-04-28 17:14:26 +01:00
# endif /* CONFIG_MIPS_MT_FPAFF */
local_irq_enable ( ) ;
}
/*
* Setup the PC , SP , and GP of a secondary processor and start it running
* smp_bootstrap is the place to resume from
* __KSTK_TOS ( idle ) is apparently the stack pointer
* ( unsigned long ) idle - > thread_info the gp
*/
static void cmp_boot_secondary ( int cpu , struct task_struct * idle )
{
struct thread_info * gp = task_thread_info ( idle ) ;
unsigned long sp = __KSTK_TOS ( idle ) ;
unsigned long pc = ( unsigned long ) & smp_bootstrap ;
unsigned long a0 = 0 ;
pr_debug ( " SMPCMP: CPU%d: %s cpu %d \n " , smp_processor_id ( ) ,
__func__ , cpu ) ;
#if 0
/* Needed? */
flush_icache_range ( ( unsigned long ) gp ,
( unsigned long ) ( gp + sizeof ( struct thread_info ) ) ) ;
# endif
2009-06-17 16:22:53 -07:00
amon_cpu_start ( cpu , pc , sp , ( unsigned long ) gp , a0 ) ;
2008-04-28 17:14:26 +01:00
}
/*
* Common setup before any secondaries are started
*/
void __init cmp_smp_setup ( void )
{
int i ;
int ncpu = 0 ;
pr_debug ( " SMPCMP: CPU%d: %s \n " , smp_processor_id ( ) , __func__ ) ;
# ifdef CONFIG_MIPS_MT_FPAFF
/* If we have an FPU, enroll ourselves in the FPU-full mask */
if ( cpu_has_fpu )
2015-03-05 10:49:17 +10:30
cpumask_set_cpu ( 0 , & mt_fpu_cpumask ) ;
2008-04-28 17:14:26 +01:00
# endif /* CONFIG_MIPS_MT_FPAFF */
for ( i = 1 ; i < NR_CPUS ; i + + ) {
if ( amon_cpu_avail ( i ) ) {
2009-09-24 09:34:47 -06:00
set_cpu_possible ( i , true ) ;
2008-04-28 17:14:26 +01:00
__cpu_number_map [ i ] = + + ncpu ;
2013-01-22 12:59:30 +01:00
__cpu_logical_map [ ncpu ] = i ;
2008-04-28 17:14:26 +01:00
}
}
if ( cpu_has_mipsmt ) {
2013-09-11 14:17:47 -05:00
unsigned int nvpe = 1 ;
# ifdef CONFIG_MIPS_MT_SMP
unsigned int mvpconf0 = read_c0_mvpconf0 ( ) ;
nvpe = ( ( mvpconf0 & MVPCONF0_PVPE ) > > MVPCONF0_PVPE_SHIFT ) + 1 ;
# endif
2008-04-28 17:14:26 +01:00
smp_num_siblings = nvpe ;
}
pr_info ( " Detected %i available secondary CPU(s) \n " , ncpu ) ;
}
void __init cmp_prepare_cpus ( unsigned int max_cpus )
{
pr_debug ( " SMPCMP: CPU%d: %s max_cpus=%d \n " ,
smp_processor_id ( ) , __func__ , max_cpus ) ;
2013-09-19 18:00:29 +01:00
# ifdef CONFIG_MIPS_MT
2008-04-28 17:14:26 +01:00
/*
* FIXME : some of these options are per - system , some per - core and
* some per - cpu
*/
mips_mt_set_cpuoptions ( ) ;
2013-09-19 18:00:29 +01:00
# endif
2008-04-28 17:14:26 +01:00
}
struct plat_smp_ops cmp_smp_ops = {
2015-12-08 13:20:28 +00:00
. send_ipi_single = mips_smp_send_ipi_single ,
. send_ipi_mask = mips_smp_send_ipi_mask ,
2008-04-28 17:14:26 +01:00
. init_secondary = cmp_init_secondary ,
. smp_finish = cmp_smp_finish ,
. boot_secondary = cmp_boot_secondary ,
. smp_setup = cmp_smp_setup ,
. prepare_cpus = cmp_prepare_cpus ,
} ;