139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle/* 239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * This program is free software; you can distribute it and/or modify it 339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * under the terms of the GNU General Public License (Version 2) as 439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * published by the Free Software Foundation. 539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * 639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * This program is distributed in the hope it will be useful, but WITHOUT 739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * for more details. 1039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * 1139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * You should have received a copy of the GNU General Public License along 1239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * with this program; if not, write to the Free Software Foundation, Inc., 1339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 1439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * 1539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * Copyright (C) 2007 MIPS Technologies, Inc. 1639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * Chris Dearman (chris@mips.com) 1739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle */ 1839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 1939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#undef DEBUG 2039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 2139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <linux/kernel.h> 2239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <linux/sched.h> 23631330f5847b3f8a7ea67d689e9f7c56833ccaa6Ralf Baechle#include <linux/smp.h> 2439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <linux/cpumask.h> 2539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <linux/interrupt.h> 2639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <linux/compiler.h> 2739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 2860063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 2939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/cacheflush.h> 3039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/cpu.h> 3139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/processor.h> 3239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/hardirq.h> 3339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/mmu_context.h> 3439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/smp.h> 3539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/time.h> 3639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/mipsregs.h> 3739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/mipsmtregs.h> 3839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#include <asm/mips_mt.h> 390365070f05f12f1648b4adf22cfb52ec7a8a371cTim Anderson#include <asm/amon.h> 400365070f05f12f1648b4adf22cfb52ec7a8a371cTim Anderson#include <asm/gic.h> 4139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 4239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlestatic void cmp_init_secondary(void) 4339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle{ 44f0cff5c86f7d3be0084eedbf449c3f47638e76f2Paul Burton struct cpuinfo_mips *c __maybe_unused = ¤t_cpu_data; 4539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 4639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* Assume GIC is present */ 4739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | 4839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle STATUSF_IP7); 4939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 5039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* Enable per-cpu interrupts: platform specific */ 5139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 52b633648c5ad3cfbda0b3daea50d2135d44899259Ralf Baechle#ifdef CONFIG_MIPS_MT_SMP 53670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin if (cpu_has_mipsmt) 54670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & 55670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin TCBIND_CURVPE; 5639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#endif 5739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle} 5839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 5939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlestatic void cmp_smp_finish(void) 6039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle{ 6139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); 6239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 6339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* CDFIXME: remove this? */ 6439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); 6539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 6639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#ifdef CONFIG_MIPS_MT_FPAFF 6739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* If we have an FPU, enroll ourselves in the FPU-full mask */ 6839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle if (cpu_has_fpu) 6939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle cpu_set(smp_processor_id(), mt_fpu_cpumask); 7039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#endif /* CONFIG_MIPS_MT_FPAFF */ 7139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 7239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle local_irq_enable(); 7339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle} 7439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 7539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle/* 7639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * Setup the PC, SP, and GP of a secondary processor and start it running 7739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * smp_bootstrap is the place to resume from 7839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * __KSTK_TOS(idle) is apparently the stack pointer 7939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * (unsigned long)idle->thread_info the gp 8039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle */ 8139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlestatic void cmp_boot_secondary(int cpu, struct task_struct *idle) 8239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle{ 8339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle struct thread_info *gp = task_thread_info(idle); 8439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle unsigned long sp = __KSTK_TOS(idle); 8539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle unsigned long pc = (unsigned long)&smp_bootstrap; 8639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle unsigned long a0 = 0; 8739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 8839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), 8939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle __func__, cpu); 9039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 9139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#if 0 9239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* Needed? */ 9339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle flush_icache_range((unsigned long)gp, 9439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle (unsigned long)(gp + sizeof(struct thread_info))); 9539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#endif 9639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 970365070f05f12f1648b4adf22cfb52ec7a8a371cTim Anderson amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0); 9839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle} 9939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 10039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle/* 10139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * Common setup before any secondaries are started 10239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle */ 10339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlevoid __init cmp_smp_setup(void) 10439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle{ 10539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle int i; 10639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle int ncpu = 0; 10739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 10839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); 10939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 11039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#ifdef CONFIG_MIPS_MT_FPAFF 11139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* If we have an FPU, enroll ourselves in the FPU-full mask */ 11239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle if (cpu_has_fpu) 11339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle cpu_set(0, mt_fpu_cpumask); 11439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle#endif /* CONFIG_MIPS_MT_FPAFF */ 11539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 11639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle for (i = 1; i < NR_CPUS; i++) { 11739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle if (amon_cpu_avail(i)) { 1184037ac6e2cb4e3148c25124b431eead4e704a4ffRusty Russell set_cpu_possible(i, true); 11939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle __cpu_number_map[i] = ++ncpu; 1207034228792cc561e79ff8600f02884bd4c80e287Ralf Baechle __cpu_logical_map[ncpu] = i; 12139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle } 12239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle } 12339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 12439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle if (cpu_has_mipsmt) { 125670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin unsigned int nvpe = 1; 126670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin#ifdef CONFIG_MIPS_MT_SMP 127670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin unsigned int mvpconf0 = read_c0_mvpconf0(); 128670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin 129670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; 130670bac3a8c201fc1f5f92ac6b4a8b42dc8172937Leonid Yegoshin#endif 13139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle smp_num_siblings = nvpe; 13239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle } 13339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle pr_info("Detected %i available secondary CPU(s)\n", ncpu); 13439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle} 13539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 13639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlevoid __init cmp_prepare_cpus(unsigned int max_cpus) 13739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle{ 13839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", 13939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle smp_processor_id(), __func__, max_cpus); 14039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 14140149889ce4d3c99fdbea6b6ca803bb872daebb5Markos Chandras#ifdef CONFIG_MIPS_MT 14239b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle /* 14339b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * FIXME: some of these options are per-system, some per-core and 14439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle * some per-cpu 14539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle */ 14639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle mips_mt_set_cpuoptions(); 14740149889ce4d3c99fdbea6b6ca803bb872daebb5Markos Chandras#endif 14840149889ce4d3c99fdbea6b6ca803bb872daebb5Markos Chandras 14939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle} 15039b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle 15139b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechlestruct plat_smp_ops cmp_smp_ops = { 15272e20142b2bf4cf1c3071e6cf49d01f55f2e1e53Paul Burton .send_ipi_single = gic_send_ipi_single, 15372e20142b2bf4cf1c3071e6cf49d01f55f2e1e53Paul Burton .send_ipi_mask = gic_send_ipi_mask, 15439b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle .init_secondary = cmp_init_secondary, 15539b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle .smp_finish = cmp_smp_finish, 15639b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle .boot_secondary = cmp_boot_secondary, 15739b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle .smp_setup = cmp_smp_setup, 15839b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle .prepare_cpus = cmp_prepare_cpus, 15939b8d5254246ac56342b72f812255c8f7a74dca9Ralf Baechle}; 160