xref: /netbsd-src/sys/external/bsd/drm2/linux/linux_stop_machine.c (revision ef3476fb5721c4ddb85643c5ce2f7cbbc30a2820)
1*ef3476fbSriastradh /*	$NetBSD: linux_stop_machine.c,v 1.4 2022/04/09 23:38:33 riastradh Exp $	*/
2dc93710eSriastradh 
3dc93710eSriastradh /*-
4dc93710eSriastradh  * Copyright (c) 2018 The NetBSD Foundation, Inc.
5dc93710eSriastradh  * All rights reserved.
6dc93710eSriastradh  *
7dc93710eSriastradh  * This code is derived from software contributed to The NetBSD Foundation
8dc93710eSriastradh  * by Taylor R. Campbell.
9dc93710eSriastradh  *
10dc93710eSriastradh  * Redistribution and use in source and binary forms, with or without
11dc93710eSriastradh  * modification, are permitted provided that the following conditions
12dc93710eSriastradh  * are met:
13dc93710eSriastradh  * 1. Redistributions of source code must retain the above copyright
14dc93710eSriastradh  *    notice, this list of conditions and the following disclaimer.
15dc93710eSriastradh  * 2. Redistributions in binary form must reproduce the above copyright
16dc93710eSriastradh  *    notice, this list of conditions and the following disclaimer in the
17dc93710eSriastradh  *    documentation and/or other materials provided with the distribution.
18dc93710eSriastradh  *
19dc93710eSriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20dc93710eSriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21dc93710eSriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22dc93710eSriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23dc93710eSriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24dc93710eSriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25dc93710eSriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26dc93710eSriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27dc93710eSriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28dc93710eSriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29dc93710eSriastradh  * POSSIBILITY OF SUCH DAMAGE.
30dc93710eSriastradh  */
31dc93710eSriastradh 
32dc93710eSriastradh #include <sys/cdefs.h>
33*ef3476fbSriastradh __KERNEL_RCSID(0, "$NetBSD: linux_stop_machine.c,v 1.4 2022/04/09 23:38:33 riastradh Exp $");
34c0ce8235Sriastradh 
35c0ce8235Sriastradh #include <sys/mutex.h> /* XXX work around cycle x86/mutex.h<->x86/intr.h */
36dc93710eSriastradh 
37dc93710eSriastradh #include <sys/atomic.h>
38dc93710eSriastradh #include <sys/intr.h>
39dc93710eSriastradh #include <sys/lock.h>
40dc93710eSriastradh #include <sys/systm.h>
41dc93710eSriastradh #include <sys/xcall.h>
42dc93710eSriastradh 
43dc93710eSriastradh #include <linux/stop_machine.h>
44dc93710eSriastradh 
45dc93710eSriastradh struct stop_machine {
46dc93710eSriastradh 	int			(*callback)(void *);
47dc93710eSriastradh 	void			*cookie;
48dc93710eSriastradh 	volatile unsigned	ncpu;
49dc93710eSriastradh 	volatile bool		done;
50dc93710eSriastradh };
51dc93710eSriastradh 
52dc93710eSriastradh static void
stop_machine_xcall(void * a,void * b)53dc93710eSriastradh stop_machine_xcall(void *a, void *b)
54dc93710eSriastradh {
55dc93710eSriastradh 	struct stop_machine *S = a;
56dc93710eSriastradh 	int s;
57dc93710eSriastradh 
58dc93710eSriastradh 	/* Block all activity on this CPU.  */
59dc93710eSriastradh 	s = splhigh();
60dc93710eSriastradh 
61dc93710eSriastradh 	/* Note that we're ready, and see whether we're the chosen one.  */
62*ef3476fbSriastradh 	membar_release();
63dc93710eSriastradh 	if (atomic_dec_uint_nv(&S->ncpu) != 0) {
64122a3e8aSriastradh 		while (!atomic_load_acquire(&S->done))
65dc93710eSriastradh 			SPINLOCK_BACKOFF_HOOK;
66dc93710eSriastradh 		goto out;
67dc93710eSriastradh 	}
68*ef3476fbSriastradh 	membar_acquire();
69dc93710eSriastradh 
70dc93710eSriastradh 	/* It's time.  Call the callback.  */
71dc93710eSriastradh 	S->callback(S->cookie);
72dc93710eSriastradh 
73dc93710eSriastradh 	/* Notify everyone else that we're done.  */
74122a3e8aSriastradh 	atomic_store_release(&S->done, true);
75dc93710eSriastradh 
76dc93710eSriastradh 	/* Allow activity again.  */
77dc93710eSriastradh out:	splx(s);
78dc93710eSriastradh }
79dc93710eSriastradh 
80dc93710eSriastradh void
stop_machine(int (* callback)(void *),void * cookie,const struct kcpuset * cpus)81dc93710eSriastradh stop_machine(int (*callback)(void *), void *cookie, const struct kcpuset *cpus)
82dc93710eSriastradh {
83dc93710eSriastradh 	struct stop_machine stop, *S = &stop;
84dc93710eSriastradh 
85dc93710eSriastradh 	KASSERT(cpus == NULL);	/* not implemented */
86dc93710eSriastradh 
87dc93710eSriastradh 	S->callback = callback;
88dc93710eSriastradh 	S->cookie = cookie;
89dc93710eSriastradh 	S->ncpu = ncpu;		/* XXX cpu hotplug */
90dc93710eSriastradh 	S->done = false;
91dc93710eSriastradh 
92dc93710eSriastradh 	xc_wait(xc_broadcast(0, stop_machine_xcall, &S, NULL));
93dc93710eSriastradh }
94