xref: /linux/arch/um/kernel/smp.c (revision 399ead3a6d76cbdd29a716660db5c84a314dab70)
1*1e4ee513STiwei Bie // SPDX-License-Identifier: GPL-2.0
2*1e4ee513STiwei Bie /*
3*1e4ee513STiwei Bie  * Copyright (C) 2025 Ant Group
4*1e4ee513STiwei Bie  * Author: Tiwei Bie <tiwei.btw@antgroup.com>
5*1e4ee513STiwei Bie  *
6*1e4ee513STiwei Bie  * Based on the previous implementation in TT mode
7*1e4ee513STiwei Bie  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
8*1e4ee513STiwei Bie  */
9*1e4ee513STiwei Bie 
10*1e4ee513STiwei Bie #include <linux/sched.h>
11*1e4ee513STiwei Bie #include <linux/sched/task.h>
12*1e4ee513STiwei Bie #include <linux/sched/task_stack.h>
13*1e4ee513STiwei Bie #include <linux/module.h>
14*1e4ee513STiwei Bie #include <linux/processor.h>
15*1e4ee513STiwei Bie #include <linux/threads.h>
16*1e4ee513STiwei Bie #include <linux/cpu.h>
17*1e4ee513STiwei Bie #include <linux/hardirq.h>
18*1e4ee513STiwei Bie #include <linux/smp.h>
19*1e4ee513STiwei Bie #include <linux/smp-internal.h>
20*1e4ee513STiwei Bie #include <init.h>
21*1e4ee513STiwei Bie #include <kern.h>
22*1e4ee513STiwei Bie #include <os.h>
23*1e4ee513STiwei Bie #include <smp.h>
24*1e4ee513STiwei Bie 
25*1e4ee513STiwei Bie enum {
26*1e4ee513STiwei Bie 	UML_IPI_RES = 0,
27*1e4ee513STiwei Bie 	UML_IPI_CALL_SINGLE,
28*1e4ee513STiwei Bie 	UML_IPI_CALL,
29*1e4ee513STiwei Bie 	UML_IPI_STOP,
30*1e4ee513STiwei Bie };
31*1e4ee513STiwei Bie 
arch_smp_send_reschedule(int cpu)32*1e4ee513STiwei Bie void arch_smp_send_reschedule(int cpu)
33*1e4ee513STiwei Bie {
34*1e4ee513STiwei Bie 	os_send_ipi(cpu, UML_IPI_RES);
35*1e4ee513STiwei Bie }
36*1e4ee513STiwei Bie 
arch_send_call_function_single_ipi(int cpu)37*1e4ee513STiwei Bie void arch_send_call_function_single_ipi(int cpu)
38*1e4ee513STiwei Bie {
39*1e4ee513STiwei Bie 	os_send_ipi(cpu, UML_IPI_CALL_SINGLE);
40*1e4ee513STiwei Bie }
41*1e4ee513STiwei Bie 
arch_send_call_function_ipi_mask(const struct cpumask * mask)42*1e4ee513STiwei Bie void arch_send_call_function_ipi_mask(const struct cpumask *mask)
43*1e4ee513STiwei Bie {
44*1e4ee513STiwei Bie 	int cpu;
45*1e4ee513STiwei Bie 
46*1e4ee513STiwei Bie 	for_each_cpu(cpu, mask)
47*1e4ee513STiwei Bie 		os_send_ipi(cpu, UML_IPI_CALL);
48*1e4ee513STiwei Bie }
49*1e4ee513STiwei Bie 
smp_send_stop(void)50*1e4ee513STiwei Bie void smp_send_stop(void)
51*1e4ee513STiwei Bie {
52*1e4ee513STiwei Bie 	int cpu, me = smp_processor_id();
53*1e4ee513STiwei Bie 
54*1e4ee513STiwei Bie 	for_each_online_cpu(cpu) {
55*1e4ee513STiwei Bie 		if (cpu == me)
56*1e4ee513STiwei Bie 			continue;
57*1e4ee513STiwei Bie 		os_send_ipi(cpu, UML_IPI_STOP);
58*1e4ee513STiwei Bie 	}
59*1e4ee513STiwei Bie }
60*1e4ee513STiwei Bie 
ipi_handler(int vector,struct uml_pt_regs * regs)61*1e4ee513STiwei Bie static void ipi_handler(int vector, struct uml_pt_regs *regs)
62*1e4ee513STiwei Bie {
63*1e4ee513STiwei Bie 	struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
64*1e4ee513STiwei Bie 	int cpu = raw_smp_processor_id();
65*1e4ee513STiwei Bie 
66*1e4ee513STiwei Bie 	irq_enter();
67*1e4ee513STiwei Bie 
68*1e4ee513STiwei Bie 	if (current->mm)
69*1e4ee513STiwei Bie 		os_alarm_process(current->mm->context.id.pid);
70*1e4ee513STiwei Bie 
71*1e4ee513STiwei Bie 	switch (vector) {
72*1e4ee513STiwei Bie 	case UML_IPI_RES:
73*1e4ee513STiwei Bie 		inc_irq_stat(irq_resched_count);
74*1e4ee513STiwei Bie 		scheduler_ipi();
75*1e4ee513STiwei Bie 		break;
76*1e4ee513STiwei Bie 
77*1e4ee513STiwei Bie 	case UML_IPI_CALL_SINGLE:
78*1e4ee513STiwei Bie 		inc_irq_stat(irq_call_count);
79*1e4ee513STiwei Bie 		generic_smp_call_function_single_interrupt();
80*1e4ee513STiwei Bie 		break;
81*1e4ee513STiwei Bie 
82*1e4ee513STiwei Bie 	case UML_IPI_CALL:
83*1e4ee513STiwei Bie 		inc_irq_stat(irq_call_count);
84*1e4ee513STiwei Bie 		generic_smp_call_function_interrupt();
85*1e4ee513STiwei Bie 		break;
86*1e4ee513STiwei Bie 
87*1e4ee513STiwei Bie 	case UML_IPI_STOP:
88*1e4ee513STiwei Bie 		set_cpu_online(cpu, false);
89*1e4ee513STiwei Bie 		while (1)
90*1e4ee513STiwei Bie 			pause();
91*1e4ee513STiwei Bie 		break;
92*1e4ee513STiwei Bie 
93*1e4ee513STiwei Bie 	default:
94*1e4ee513STiwei Bie 		pr_err("CPU#%d received unknown IPI (vector=%d)!\n", cpu, vector);
95*1e4ee513STiwei Bie 		break;
96*1e4ee513STiwei Bie 	}
97*1e4ee513STiwei Bie 
98*1e4ee513STiwei Bie 	irq_exit();
99*1e4ee513STiwei Bie 	set_irq_regs(old_regs);
100*1e4ee513STiwei Bie }
101*1e4ee513STiwei Bie 
uml_ipi_handler(int vector)102*1e4ee513STiwei Bie void uml_ipi_handler(int vector)
103*1e4ee513STiwei Bie {
104*1e4ee513STiwei Bie 	struct uml_pt_regs r = { .is_user = 0 };
105*1e4ee513STiwei Bie 
106*1e4ee513STiwei Bie 	preempt_disable();
107*1e4ee513STiwei Bie 	ipi_handler(vector, &r);
108*1e4ee513STiwei Bie 	preempt_enable();
109*1e4ee513STiwei Bie }
110*1e4ee513STiwei Bie 
111*1e4ee513STiwei Bie /* AP states used only during CPU startup */
112*1e4ee513STiwei Bie enum {
113*1e4ee513STiwei Bie 	UML_CPU_PAUSED = 0,
114*1e4ee513STiwei Bie 	UML_CPU_RUNNING,
115*1e4ee513STiwei Bie };
116*1e4ee513STiwei Bie 
117*1e4ee513STiwei Bie static int cpu_states[NR_CPUS];
118*1e4ee513STiwei Bie 
start_secondary(void * unused)119*1e4ee513STiwei Bie static int start_secondary(void *unused)
120*1e4ee513STiwei Bie {
121*1e4ee513STiwei Bie 	int err, cpu = raw_smp_processor_id();
122*1e4ee513STiwei Bie 
123*1e4ee513STiwei Bie 	notify_cpu_starting(cpu);
124*1e4ee513STiwei Bie 	set_cpu_online(cpu, true);
125*1e4ee513STiwei Bie 
126*1e4ee513STiwei Bie 	err = um_setup_timer();
127*1e4ee513STiwei Bie 	if (err)
128*1e4ee513STiwei Bie 		panic("CPU#%d failed to setup timer, err = %d", cpu, err);
129*1e4ee513STiwei Bie 
130*1e4ee513STiwei Bie 	local_irq_enable();
131*1e4ee513STiwei Bie 
132*1e4ee513STiwei Bie 	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
133*1e4ee513STiwei Bie 
134*1e4ee513STiwei Bie 	return 0;
135*1e4ee513STiwei Bie }
136*1e4ee513STiwei Bie 
uml_start_secondary(void * opaque)137*1e4ee513STiwei Bie void uml_start_secondary(void *opaque)
138*1e4ee513STiwei Bie {
139*1e4ee513STiwei Bie 	int cpu = raw_smp_processor_id();
140*1e4ee513STiwei Bie 	struct mm_struct *mm = &init_mm;
141*1e4ee513STiwei Bie 	struct task_struct *idle;
142*1e4ee513STiwei Bie 
143*1e4ee513STiwei Bie 	stack_protections((unsigned long) &cpu_irqstacks[cpu]);
144*1e4ee513STiwei Bie 	set_sigstack(&cpu_irqstacks[cpu], THREAD_SIZE);
145*1e4ee513STiwei Bie 
146*1e4ee513STiwei Bie 	set_cpu_present(cpu, true);
147*1e4ee513STiwei Bie 	os_futex_wait(&cpu_states[cpu], UML_CPU_PAUSED);
148*1e4ee513STiwei Bie 
149*1e4ee513STiwei Bie 	smp_rmb(); /* paired with smp_wmb() in __cpu_up() */
150*1e4ee513STiwei Bie 
151*1e4ee513STiwei Bie 	idle = cpu_tasks[cpu];
152*1e4ee513STiwei Bie 	idle->thread_info.cpu = cpu;
153*1e4ee513STiwei Bie 
154*1e4ee513STiwei Bie 	mmgrab(mm);
155*1e4ee513STiwei Bie 	idle->active_mm = mm;
156*1e4ee513STiwei Bie 
157*1e4ee513STiwei Bie 	idle->thread.request.thread.proc = start_secondary;
158*1e4ee513STiwei Bie 	idle->thread.request.thread.arg = NULL;
159*1e4ee513STiwei Bie 
160*1e4ee513STiwei Bie 	new_thread(task_stack_page(idle), &idle->thread.switch_buf,
161*1e4ee513STiwei Bie 		   new_thread_handler);
162*1e4ee513STiwei Bie 	os_start_secondary(opaque, &idle->thread.switch_buf);
163*1e4ee513STiwei Bie }
164*1e4ee513STiwei Bie 
smp_prepare_cpus(unsigned int max_cpus)165*1e4ee513STiwei Bie void __init smp_prepare_cpus(unsigned int max_cpus)
166*1e4ee513STiwei Bie {
167*1e4ee513STiwei Bie 	int err, cpu, me = smp_processor_id();
168*1e4ee513STiwei Bie 	unsigned long deadline;
169*1e4ee513STiwei Bie 
170*1e4ee513STiwei Bie 	os_init_smp();
171*1e4ee513STiwei Bie 
172*1e4ee513STiwei Bie 	for_each_possible_cpu(cpu) {
173*1e4ee513STiwei Bie 		if (cpu == me)
174*1e4ee513STiwei Bie 			continue;
175*1e4ee513STiwei Bie 
176*1e4ee513STiwei Bie 		pr_debug("Booting processor %d...\n", cpu);
177*1e4ee513STiwei Bie 		err = os_start_cpu_thread(cpu);
178*1e4ee513STiwei Bie 		if (err) {
179*1e4ee513STiwei Bie 			pr_crit("CPU#%d failed to start cpu thread, err = %d",
180*1e4ee513STiwei Bie 				cpu, err);
181*1e4ee513STiwei Bie 			continue;
182*1e4ee513STiwei Bie 		}
183*1e4ee513STiwei Bie 
184*1e4ee513STiwei Bie 		deadline = jiffies + msecs_to_jiffies(1000);
185*1e4ee513STiwei Bie 		spin_until_cond(cpu_present(cpu) ||
186*1e4ee513STiwei Bie 				time_is_before_jiffies(deadline));
187*1e4ee513STiwei Bie 
188*1e4ee513STiwei Bie 		if (!cpu_present(cpu))
189*1e4ee513STiwei Bie 			pr_crit("CPU#%d failed to boot\n", cpu);
190*1e4ee513STiwei Bie 	}
191*1e4ee513STiwei Bie }
192*1e4ee513STiwei Bie 
__cpu_up(unsigned int cpu,struct task_struct * tidle)193*1e4ee513STiwei Bie int __cpu_up(unsigned int cpu, struct task_struct *tidle)
194*1e4ee513STiwei Bie {
195*1e4ee513STiwei Bie 	cpu_tasks[cpu] = tidle;
196*1e4ee513STiwei Bie 	smp_wmb(); /* paired with smp_rmb() in uml_start_secondary() */
197*1e4ee513STiwei Bie 	cpu_states[cpu] = UML_CPU_RUNNING;
198*1e4ee513STiwei Bie 	os_futex_wake(&cpu_states[cpu]);
199*1e4ee513STiwei Bie 	spin_until_cond(cpu_online(cpu));
200*1e4ee513STiwei Bie 
201*1e4ee513STiwei Bie 	return 0;
202*1e4ee513STiwei Bie }
203*1e4ee513STiwei Bie 
smp_cpus_done(unsigned int max_cpus)204*1e4ee513STiwei Bie void __init smp_cpus_done(unsigned int max_cpus)
205*1e4ee513STiwei Bie {
206*1e4ee513STiwei Bie }
207*1e4ee513STiwei Bie 
208*1e4ee513STiwei Bie /* Set in uml_ncpus_setup */
209*1e4ee513STiwei Bie int uml_ncpus = 1;
210*1e4ee513STiwei Bie 
prefill_possible_map(void)211*1e4ee513STiwei Bie void __init prefill_possible_map(void)
212*1e4ee513STiwei Bie {
213*1e4ee513STiwei Bie 	int cpu;
214*1e4ee513STiwei Bie 
215*1e4ee513STiwei Bie 	for (cpu = 0; cpu < uml_ncpus; cpu++)
216*1e4ee513STiwei Bie 		set_cpu_possible(cpu, true);
217*1e4ee513STiwei Bie 	for (; cpu < NR_CPUS; cpu++)
218*1e4ee513STiwei Bie 		set_cpu_possible(cpu, false);
219*1e4ee513STiwei Bie }
220*1e4ee513STiwei Bie 
uml_ncpus_setup(char * line,int * add)221*1e4ee513STiwei Bie static int __init uml_ncpus_setup(char *line, int *add)
222*1e4ee513STiwei Bie {
223*1e4ee513STiwei Bie 	*add = 0;
224*1e4ee513STiwei Bie 
225*1e4ee513STiwei Bie 	if (kstrtoint(line, 10, &uml_ncpus)) {
226*1e4ee513STiwei Bie 		os_warn("%s: Couldn't parse '%s'\n", __func__, line);
227*1e4ee513STiwei Bie 		return -1;
228*1e4ee513STiwei Bie 	}
229*1e4ee513STiwei Bie 
230*1e4ee513STiwei Bie 	uml_ncpus = clamp(uml_ncpus, 1, NR_CPUS);
231*1e4ee513STiwei Bie 
232*1e4ee513STiwei Bie 	return 0;
233*1e4ee513STiwei Bie }
234*1e4ee513STiwei Bie 
235*1e4ee513STiwei Bie __uml_setup("ncpus=", uml_ncpus_setup,
236*1e4ee513STiwei Bie "ncpus=<# of desired CPUs>\n"
237*1e4ee513STiwei Bie "    This tells UML how many virtual processors to start. The maximum\n"
238*1e4ee513STiwei Bie "    number of supported virtual processors can be obtained by querying\n"
239*1e4ee513STiwei Bie "    the CONFIG_NR_CPUS option using --showconfig.\n\n"
240*1e4ee513STiwei Bie );
241*1e4ee513STiwei Bie 
242*1e4ee513STiwei Bie EXPORT_SYMBOL(uml_curr_cpu);
243