xref: /freebsd/sys/kern/subr_smp.c (revision d2387d42b8da231a5b95cbc313825fb2aadf26f6)
1 /*
2  * Copyright (c) 2001
3  *	John Baldwin <jhb@FreeBSD.org>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BALDWIN AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN BALDWIN OR THE VOICES IN HIS HEAD
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * This module holds the global variables and machine independent functions
32  * used for the kernel SMP support.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/ktr.h>
42 #include <sys/proc.h>
43 #include <sys/bus.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/pcpu.h>
47 #include <sys/smp.h>
48 #include <sys/sysctl.h>
49 
50 #include <machine/smp.h>
51 
52 #ifdef SMP
53 volatile cpumask_t stopped_cpus;
54 volatile cpumask_t started_cpus;
55 
56 void (*cpustop_restartfunc)(void);
57 #endif
58 
59 int mp_ncpus;
60 /* export this for libkvm consumers. */
61 int mp_maxcpus = MAXCPU;
62 
63 struct cpu_top *smp_topology;
64 volatile int smp_started;
65 cpumask_t all_cpus;
66 u_int mp_maxid;
67 
68 SYSCTL_NODE(_kern, OID_AUTO, smp, CTLFLAG_RD, NULL, "Kernel SMP");
69 
70 SYSCTL_INT(_kern_smp, OID_AUTO, maxcpus, CTLFLAG_RD, &mp_maxcpus, 0,
71     "Max number of CPUs that the system was compiled for.");
72 
73 int smp_active = 0;	/* are the APs allowed to run? */
74 SYSCTL_INT(_kern_smp, OID_AUTO, active, CTLFLAG_RW, &smp_active, 0,
75     "Number of Auxillary Processors (APs) that were successfully started");
76 
77 int smp_disabled = 0;	/* has smp been disabled? */
78 SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN, &smp_disabled, 0,
79     "SMP has been disabled from the loader");
80 TUNABLE_INT("kern.smp.disabled", &smp_disabled);
81 
82 int smp_cpus = 1;	/* how many cpu's running */
83 SYSCTL_INT(_kern_smp, OID_AUTO, cpus, CTLFLAG_RD, &smp_cpus, 0,
84     "Number of CPUs online");
85 
86 #if !__sparc64__ && !__powerpc__
87 static void	cpu_identify(driver_t *driver, device_t parent);
88 static device_t	cpu_add_child(device_t bus, int order, const char *name,
89 			int unit);
90 
91 static device_method_t cpu_methods[] = {
92 	/* Device interface */
93 	DEVMETHOD(device_identify,	cpu_identify),
94 	DEVMETHOD(device_probe,		bus_generic_probe),
95 	DEVMETHOD(device_attach,	bus_generic_attach),
96 	DEVMETHOD(device_detach,	bus_generic_detach),
97 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
98 	DEVMETHOD(device_suspend,	bus_generic_suspend),
99 	DEVMETHOD(device_resume,	bus_generic_resume),
100 
101 	/* Bus interface */
102 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
103 	DEVMETHOD(bus_add_child,	cpu_add_child),
104 	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
105 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
106 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
107 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
108 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
109 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
110 #ifdef notyet
111 	DEVMETHOD(bus_set_resource,	bus_generic_set_resource),
112 	DEVMETHOD(bus_get_resource,	bus_generic_get_resource),
113 	DEVMETHOD(bus_delete_resource,	bus_generic_delete_resource),
114 #endif
115 
116 	{ 0, 0 }
117 };
118 
119 static driver_t cpu_driver = {
120 	"cpu",
121 	cpu_methods,
122 	1,		/* no softc */
123 };
124 static devclass_t cpu_devclass;
125 DRIVER_MODULE(cpu, nexus, cpu_driver, cpu_devclass, 0, 0);
126 #endif
127 
128 #ifdef SMP
129 /* Enable forwarding of a signal to a process running on a different CPU */
130 static int forward_signal_enabled = 1;
131 SYSCTL_INT(_kern_smp, OID_AUTO, forward_signal_enabled, CTLFLAG_RW,
132 	   &forward_signal_enabled, 0,
133 	   "Forwarding of a signal to a process on a different CPU");
134 
135 /* Enable forwarding of roundrobin to all other cpus */
136 static int forward_roundrobin_enabled = 1;
137 SYSCTL_INT(_kern_smp, OID_AUTO, forward_roundrobin_enabled, CTLFLAG_RW,
138 	   &forward_roundrobin_enabled, 0,
139 	   "Forwarding of roundrobin to all other CPUs");
140 
141 /* Variables needed for SMP rendezvous. */
142 static void (*smp_rv_setup_func)(void *arg);
143 static void (*smp_rv_action_func)(void *arg);
144 static void (*smp_rv_teardown_func)(void *arg);
145 static void *smp_rv_func_arg;
146 static volatile int smp_rv_waiters[2];
147 static struct mtx smp_rv_mtx;
148 
149 /*
150  * Let the MD SMP code initialize mp_maxid very early if it can.
151  */
152 static void
153 mp_setmaxid(void *dummy)
154 {
155 	cpu_mp_setmaxid();
156 }
157 SYSINIT(cpu_mp_setmaxid, SI_SUB_TUNABLES, SI_ORDER_FIRST, mp_setmaxid, NULL)
158 
159 /*
160  * Call the MD SMP initialization code.
161  */
162 static void
163 mp_start(void *dummy)
164 {
165 
166 	/* Probe for MP hardware. */
167 	if (smp_disabled != 0 || cpu_mp_probe() == 0) {
168 		mp_ncpus = 1;
169 		all_cpus = PCPU_GET(cpumask);
170 		return;
171 	}
172 
173 	mtx_init(&smp_rv_mtx, "smp rendezvous", NULL, MTX_SPIN);
174 	cpu_mp_start();
175 	printf("FreeBSD/SMP: Multiprocessor System Detected: %d CPUs\n",
176 	    mp_ncpus);
177 	cpu_mp_announce();
178 }
179 SYSINIT(cpu_mp, SI_SUB_CPU, SI_ORDER_SECOND, mp_start, NULL)
180 
181 void
182 forward_signal(struct thread *td)
183 {
184 	int id;
185 
186 	/*
187 	 * signotify() has already set TDF_ASTPENDING and TDF_NEEDSIGCHECK on
188 	 * this thread, so all we need to do is poke it if it is currently
189 	 * executing so that it executes ast().
190 	 */
191 	mtx_assert(&sched_lock, MA_OWNED);
192 	KASSERT(TD_IS_RUNNING(td),
193 	    ("forward_signal: thread is not TDS_RUNNING"));
194 
195 	CTR1(KTR_SMP, "forward_signal(%p)", td->td_proc);
196 
197 	if (!smp_started || cold || panicstr)
198 		return;
199 	if (!forward_signal_enabled)
200 		return;
201 
202 	/* No need to IPI ourself. */
203 	if (td == curthread)
204 		return;
205 
206 	id = td->td_oncpu;
207 	if (id == NOCPU)
208 		return;
209 	ipi_selected(1 << id, IPI_AST);
210 }
211 
212 void
213 forward_roundrobin(void)
214 {
215 	struct pcpu *pc;
216 	struct thread *td;
217 	cpumask_t id, map;
218 
219 	mtx_assert(&sched_lock, MA_OWNED);
220 
221 	CTR0(KTR_SMP, "forward_roundrobin()");
222 
223 	if (!smp_started || cold || panicstr)
224 		return;
225 	if (!forward_roundrobin_enabled)
226 		return;
227 	map = 0;
228 	SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
229 		td = pc->pc_curthread;
230 		id = pc->pc_cpumask;
231 		if (id != PCPU_GET(cpumask) && (id & stopped_cpus) == 0 &&
232 		    td != pc->pc_idlethread) {
233 			td->td_flags |= TDF_NEEDRESCHED;
234 			map |= id;
235 		}
236 	}
237 	ipi_selected(map, IPI_AST);
238 }
239 
240 /*
241  * When called the executing CPU will send an IPI to all other CPUs
242  *  requesting that they halt execution.
243  *
244  * Usually (but not necessarily) called with 'other_cpus' as its arg.
245  *
246  *  - Signals all CPUs in map to stop.
247  *  - Waits for each to stop.
248  *
249  * Returns:
250  *  -1: error
251  *   0: NA
252  *   1: ok
253  *
254  * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs
255  *            from executing at same time.
256  */
257 int
258 stop_cpus(cpumask_t map)
259 {
260 	int i;
261 
262 	if (!smp_started)
263 		return 0;
264 
265 	CTR1(KTR_SMP, "stop_cpus(%x)", map);
266 
267 	/* send the stop IPI to all CPUs in map */
268 	ipi_selected(map, IPI_STOP);
269 
270 	i = 0;
271 	while ((atomic_load_acq_int(&stopped_cpus) & map) != map) {
272 		/* spin */
273 		i++;
274 #ifdef DIAGNOSTIC
275 		if (i == 100000) {
276 			printf("timeout stopping cpus\n");
277 			break;
278 		}
279 #endif
280 	}
281 
282 	return 1;
283 }
284 
285 
286 /*
287  * Called by a CPU to restart stopped CPUs.
288  *
289  * Usually (but not necessarily) called with 'stopped_cpus' as its arg.
290  *
291  *  - Signals all CPUs in map to restart.
292  *  - Waits for each to restart.
293  *
294  * Returns:
295  *  -1: error
296  *   0: NA
297  *   1: ok
298  */
299 int
300 restart_cpus(cpumask_t map)
301 {
302 
303 	if (!smp_started)
304 		return 0;
305 
306 	CTR1(KTR_SMP, "restart_cpus(%x)", map);
307 
308 	/* signal other cpus to restart */
309 	atomic_store_rel_int(&started_cpus, map);
310 
311 	/* wait for each to clear its bit */
312 	while ((atomic_load_acq_int(&stopped_cpus) & map) != 0)
313 		;	/* nothing */
314 
315 	return 1;
316 }
317 
318 /*
319  * All-CPU rendezvous.  CPUs are signalled, all execute the setup function
320  * (if specified), rendezvous, execute the action function (if specified),
321  * rendezvous again, execute the teardown function (if specified), and then
322  * resume.
323  *
324  * Note that the supplied external functions _must_ be reentrant and aware
325  * that they are running in parallel and in an unknown lock context.
326  */
327 void
328 smp_rendezvous_action(void)
329 {
330 
331 	/* setup function */
332 	if (smp_rv_setup_func != NULL)
333 		smp_rv_setup_func(smp_rv_func_arg);
334 	/* spin on entry rendezvous */
335 	atomic_add_int(&smp_rv_waiters[0], 1);
336 	while (atomic_load_acq_int(&smp_rv_waiters[0]) < mp_ncpus)
337 		;	/* nothing */
338 	/* action function */
339 	if (smp_rv_action_func != NULL)
340 		smp_rv_action_func(smp_rv_func_arg);
341 	/* spin on exit rendezvous */
342 	atomic_add_int(&smp_rv_waiters[1], 1);
343 	while (atomic_load_acq_int(&smp_rv_waiters[1]) < mp_ncpus)
344 		;	/* nothing */
345 	/* teardown function */
346 	if (smp_rv_teardown_func != NULL)
347 		smp_rv_teardown_func(smp_rv_func_arg);
348 }
349 
350 void
351 smp_rendezvous(void (* setup_func)(void *),
352 	       void (* action_func)(void *),
353 	       void (* teardown_func)(void *),
354 	       void *arg)
355 {
356 
357 	if (!smp_started) {
358 		if (setup_func != NULL)
359 			setup_func(arg);
360 		if (action_func != NULL)
361 			action_func(arg);
362 		if (teardown_func != NULL)
363 			teardown_func(arg);
364 		return;
365 	}
366 
367 	/* obtain rendezvous lock */
368 	mtx_lock_spin(&smp_rv_mtx);
369 
370 	/* set static function pointers */
371 	smp_rv_setup_func = setup_func;
372 	smp_rv_action_func = action_func;
373 	smp_rv_teardown_func = teardown_func;
374 	smp_rv_func_arg = arg;
375 	smp_rv_waiters[0] = 0;
376 	smp_rv_waiters[1] = 0;
377 
378 	/* signal other processors, which will enter the IPI with interrupts off */
379 	ipi_all_but_self(IPI_RENDEZVOUS);
380 
381 	/* call executor function */
382 	smp_rendezvous_action();
383 
384 	/* release lock */
385 	mtx_unlock_spin(&smp_rv_mtx);
386 }
387 #else /* !SMP */
388 
389 /*
390  * Provide dummy SMP support for UP kernels.  Modules that need to use SMP
391  * APIs will still work using this dummy support.
392  */
393 static void
394 mp_setvariables_for_up(void *dummy)
395 {
396 	mp_ncpus = 1;
397 	mp_maxid = PCPU_GET(cpuid);
398 	all_cpus = PCPU_GET(cpumask);
399 	KASSERT(PCPU_GET(cpuid) == 0, ("UP must have a CPU ID of zero"));
400 }
401 SYSINIT(cpu_mp_setvariables, SI_SUB_TUNABLES, SI_ORDER_FIRST,
402     mp_setvariables_for_up, NULL)
403 
404 void
405 smp_rendezvous(void (* setup_func)(void *),
406 	       void (* action_func)(void *),
407 	       void (* teardown_func)(void *),
408 	       void *arg)
409 {
410 
411 	if (setup_func != NULL)
412 		setup_func(arg);
413 	if (action_func != NULL)
414 		action_func(arg);
415 	if (teardown_func != NULL)
416 		teardown_func(arg);
417 }
418 #endif /* SMP */
419 
420 #if !__sparc64__ && !__powerpc__
421 static void
422 cpu_identify(driver_t *driver, device_t parent)
423 {
424 	struct pcpu *pc;
425 	int i;
426 
427 	/* Protect against multiple scans of the bus. */
428 	if (!cold || device_find_child(parent, "cpu", 0) != NULL)
429 		return;
430 
431 	for (i = 0; i <= mp_maxid; i++)
432 		if (!CPU_ABSENT(i)) {
433 			pc = pcpu_find(i);
434 			KASSERT(pc != NULL, ("pcpu_find failed"));
435 			pc->pc_device = BUS_ADD_CHILD(parent, 0, "cpu", i);
436 			if (pc->pc_device == NULL)
437 				panic("failed adding cpu child");
438 		}
439 }
440 
441 static device_t
442 cpu_add_child(device_t bus, int order, const char *name, int unit)
443 {
444 	return (device_add_child_ordered(bus, order, name, unit));
445 }
446 #endif
447