smp-cmp.c (3630B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * 4 * Copyright (C) 2007 MIPS Technologies, Inc. 5 * Chris Dearman (chris@mips.com) 6 */ 7 8#undef DEBUG 9 10#include <linux/kernel.h> 11#include <linux/sched/task_stack.h> 12#include <linux/smp.h> 13#include <linux/cpumask.h> 14#include <linux/interrupt.h> 15#include <linux/compiler.h> 16 17#include <linux/atomic.h> 18#include <asm/cacheflush.h> 19#include <asm/cpu.h> 20#include <asm/processor.h> 21#include <asm/hardirq.h> 22#include <asm/mmu_context.h> 23#include <asm/smp.h> 24#include <asm/time.h> 25#include <asm/mipsregs.h> 26#include <asm/mipsmtregs.h> 27#include <asm/mips_mt.h> 28#include <asm/amon.h> 29 30static void cmp_init_secondary(void) 31{ 32 struct cpuinfo_mips *c __maybe_unused = ¤t_cpu_data; 33 34 /* Assume GIC is present */ 35 change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | 36 STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); 37 38 /* Enable per-cpu interrupts: platform specific */ 39 40#ifdef CONFIG_MIPS_MT_SMP 41 if (cpu_has_mipsmt) 42 cpu_set_vpe_id(c, (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & 43 TCBIND_CURVPE); 44#endif 45} 46 47static void cmp_smp_finish(void) 48{ 49 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); 50 51 /* CDFIXME: remove this? */ 52 write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); 53 54#ifdef CONFIG_MIPS_MT_FPAFF 55 /* If we have an FPU, enroll ourselves in the FPU-full mask */ 56 if (cpu_has_fpu) 57 cpumask_set_cpu(smp_processor_id(), &mt_fpu_cpumask); 58#endif /* CONFIG_MIPS_MT_FPAFF */ 59 60 local_irq_enable(); 61} 62 63/* 64 * Setup the PC, SP, and GP of a secondary processor and start it running 65 * smp_bootstrap is the place to resume from 66 * __KSTK_TOS(idle) is apparently the stack pointer 67 * (unsigned long)idle->thread_info the gp 68 */ 69static int cmp_boot_secondary(int cpu, struct task_struct *idle) 70{ 71 struct thread_info *gp = task_thread_info(idle); 72 unsigned long sp = __KSTK_TOS(idle); 73 unsigned long pc = (unsigned long)&smp_bootstrap; 74 unsigned long a0 = 0; 75 76 pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), 77 __func__, cpu); 78 79#if 0 80 /* Needed? */ 81 flush_icache_range((unsigned long)gp, 82 (unsigned long)(gp + sizeof(struct thread_info))); 83#endif 84 85 amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0); 86 return 0; 87} 88 89/* 90 * Common setup before any secondaries are started 91 */ 92void __init cmp_smp_setup(void) 93{ 94 int i; 95 int ncpu = 0; 96 97 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); 98 99#ifdef CONFIG_MIPS_MT_FPAFF 100 /* If we have an FPU, enroll ourselves in the FPU-full mask */ 101 if (cpu_has_fpu) 102 cpumask_set_cpu(0, &mt_fpu_cpumask); 103#endif /* CONFIG_MIPS_MT_FPAFF */ 104 105 for (i = 1; i < NR_CPUS; i++) { 106 if (amon_cpu_avail(i)) { 107 set_cpu_possible(i, true); 108 __cpu_number_map[i] = ++ncpu; 109 __cpu_logical_map[ncpu] = i; 110 } 111 } 112 113 if (cpu_has_mipsmt) { 114 unsigned int nvpe = 1; 115#ifdef CONFIG_MIPS_MT_SMP 116 unsigned int mvpconf0 = read_c0_mvpconf0(); 117 118 nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; 119#endif 120 smp_num_siblings = nvpe; 121 } 122 pr_info("Detected %i available secondary CPU(s)\n", ncpu); 123} 124 125void __init cmp_prepare_cpus(unsigned int max_cpus) 126{ 127 pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", 128 smp_processor_id(), __func__, max_cpus); 129 130#ifdef CONFIG_MIPS_MT 131 /* 132 * FIXME: some of these options are per-system, some per-core and 133 * some per-cpu 134 */ 135 mips_mt_set_cpuoptions(); 136#endif 137 138} 139 140const struct plat_smp_ops cmp_smp_ops = { 141 .send_ipi_single = mips_smp_send_ipi_single, 142 .send_ipi_mask = mips_smp_send_ipi_mask, 143 .init_secondary = cmp_init_secondary, 144 .smp_finish = cmp_smp_finish, 145 .boot_secondary = cmp_boot_secondary, 146 .smp_setup = cmp_smp_setup, 147 .prepare_cpus = cmp_prepare_cpus, 148};