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