1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (C) 2007 MIPS Technologies, Inc.
5 * Chris Dearman (chris@mips.com)
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>
17 #include <linux/atomic.h>
18 #include <asm/cacheflush.h>
20 #include <asm/processor.h>
21 #include <asm/hardirq.h>
22 #include <asm/mmu_context.h>
25 #include <asm/mipsregs.h>
26 #include <asm/mipsmtregs.h>
27 #include <asm/mips_mt.h>
30 static void cmp_init_secondary(void)
32 struct cpuinfo_mips
*c __maybe_unused
= ¤t_cpu_data
;
34 /* Assume GIC is present */
35 change_c0_status(ST0_IM
, STATUSF_IP2
| STATUSF_IP3
| STATUSF_IP4
|
36 STATUSF_IP5
| STATUSF_IP6
| STATUSF_IP7
);
38 /* Enable per-cpu interrupts: platform specific */
40 #ifdef CONFIG_MIPS_MT_SMP
42 cpu_set_vpe_id(c
, (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT
) &
47 static void cmp_smp_finish(void)
49 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__
);
51 /* CDFIXME: remove this? */
52 write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency
/ HZ
));
54 #ifdef CONFIG_MIPS_MT_FPAFF
55 /* If we have an FPU, enroll ourselves in the FPU-full mask */
57 cpumask_set_cpu(smp_processor_id(), &mt_fpu_cpumask
);
58 #endif /* CONFIG_MIPS_MT_FPAFF */
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
69 static int cmp_boot_secondary(int cpu
, struct task_struct
*idle
)
71 struct thread_info
*gp
= task_thread_info(idle
);
72 unsigned long sp
= __KSTK_TOS(idle
);
73 unsigned long pc
= (unsigned long)&smp_bootstrap
;
76 pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
81 flush_icache_range((unsigned long)gp
,
82 (unsigned long)(gp
+ sizeof(struct thread_info
)));
85 amon_cpu_start(cpu
, pc
, sp
, (unsigned long)gp
, a0
);
90 * Common setup before any secondaries are started
92 void __init
cmp_smp_setup(void)
97 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__
);
99 #ifdef CONFIG_MIPS_MT_FPAFF
100 /* If we have an FPU, enroll ourselves in the FPU-full mask */
102 cpumask_set_cpu(0, &mt_fpu_cpumask
);
103 #endif /* CONFIG_MIPS_MT_FPAFF */
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
;
113 if (cpu_has_mipsmt
) {
114 unsigned int nvpe
= 1;
115 #ifdef CONFIG_MIPS_MT_SMP
116 unsigned int mvpconf0
= read_c0_mvpconf0();
118 nvpe
= ((mvpconf0
& MVPCONF0_PVPE
) >> MVPCONF0_PVPE_SHIFT
) + 1;
120 smp_num_siblings
= nvpe
;
122 pr_info("Detected %i available secondary CPU(s)\n", ncpu
);
125 void __init
cmp_prepare_cpus(unsigned int max_cpus
)
127 pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
128 smp_processor_id(), __func__
, max_cpus
);
130 #ifdef CONFIG_MIPS_MT
132 * FIXME: some of these options are per-system, some per-core and
135 mips_mt_set_cpuoptions();
140 const 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
,