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