1*a355028fSad /* $NetBSD: subr_pserialize.c,v 1.24 2023/10/04 20:28:06 ad Exp $ */
244968cbaSchristos
344968cbaSchristos /*-
4*a355028fSad * Copyright (c) 2010, 2011, 2023 The NetBSD Foundation, Inc.
544968cbaSchristos * All rights reserved.
644968cbaSchristos *
744968cbaSchristos * Redistribution and use in source and binary forms, with or without
844968cbaSchristos * modification, are permitted provided that the following conditions
944968cbaSchristos * are met:
1044968cbaSchristos * 1. Redistributions of source code must retain the above copyright
1144968cbaSchristos * notice, this list of conditions and the following disclaimer.
1244968cbaSchristos * 2. Redistributions in binary form must reproduce the above copyright
1344968cbaSchristos * notice, this list of conditions and the following disclaimer in the
1444968cbaSchristos * documentation and/or other materials provided with the distribution.
1544968cbaSchristos *
1644968cbaSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1744968cbaSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1844968cbaSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1944968cbaSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2044968cbaSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2144968cbaSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2244968cbaSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2344968cbaSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2444968cbaSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2544968cbaSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2644968cbaSchristos * POSSIBILITY OF SUCH DAMAGE.
2744968cbaSchristos */
2844968cbaSchristos
2944968cbaSchristos /*
3044968cbaSchristos * Passive serialization.
3144968cbaSchristos */
3244968cbaSchristos
3344968cbaSchristos #include <sys/cdefs.h>
34*a355028fSad __KERNEL_RCSID(0, "$NetBSD: subr_pserialize.c,v 1.24 2023/10/04 20:28:06 ad Exp $");
3544968cbaSchristos
3644968cbaSchristos #include <sys/param.h>
3783045fafSriastradh
38a0c864ecSriastradh #include <sys/atomic.h>
3944968cbaSchristos #include <sys/cpu.h>
407508af71She #include <sys/evcnt.h>
4183045fafSriastradh #include <sys/kernel.h>
4244968cbaSchristos #include <sys/kmem.h>
4383045fafSriastradh #include <sys/lwp.h>
44d5dccc25Sriastradh #include <sys/mutex.h>
4544968cbaSchristos #include <sys/pserialize.h>
4644968cbaSchristos #include <sys/xcall.h>
4744968cbaSchristos
4844968cbaSchristos struct pserialize {
4997eadbd1Sriastradh char psz_dummy;
5044968cbaSchristos };
5144968cbaSchristos
52d5dccc25Sriastradh static kmutex_t psz_lock __cacheline_aligned;
536f17d02bSriastradh static struct evcnt psz_ev_excl __cacheline_aligned =
546f17d02bSriastradh EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pserialize", "exclusive access");
556f17d02bSriastradh EVCNT_ATTACH_STATIC(psz_ev_excl);
5644968cbaSchristos
5744968cbaSchristos /*
5844968cbaSchristos * pserialize_init:
5944968cbaSchristos *
6044968cbaSchristos * Initialize passive serialization structures.
6144968cbaSchristos */
6244968cbaSchristos void
pserialize_init(void)6344968cbaSchristos pserialize_init(void)
6444968cbaSchristos {
6544968cbaSchristos
66d5dccc25Sriastradh mutex_init(&psz_lock, MUTEX_DEFAULT, IPL_NONE);
6744968cbaSchristos }
6844968cbaSchristos
6944968cbaSchristos /*
7044968cbaSchristos * pserialize_create:
7144968cbaSchristos *
7244968cbaSchristos * Create and initialize a passive serialization object.
7344968cbaSchristos */
7444968cbaSchristos pserialize_t
pserialize_create(void)7544968cbaSchristos pserialize_create(void)
7644968cbaSchristos {
7744968cbaSchristos pserialize_t psz;
7844968cbaSchristos
79a0c864ecSriastradh psz = kmem_zalloc(sizeof(*psz), KM_SLEEP);
8044968cbaSchristos return psz;
8144968cbaSchristos }
8244968cbaSchristos
8344968cbaSchristos /*
8444968cbaSchristos * pserialize_destroy:
8544968cbaSchristos *
8644968cbaSchristos * Destroy a passive serialization object.
8744968cbaSchristos */
8844968cbaSchristos void
pserialize_destroy(pserialize_t psz)8944968cbaSchristos pserialize_destroy(pserialize_t psz)
9044968cbaSchristos {
9144968cbaSchristos
92a0c864ecSriastradh kmem_free(psz, sizeof(*psz));
9344968cbaSchristos }
9444968cbaSchristos
9544968cbaSchristos /*
9644968cbaSchristos * pserialize_perform:
9744968cbaSchristos *
9897eadbd1Sriastradh * Perform the write side of passive serialization.
9944968cbaSchristos */
10044968cbaSchristos void
pserialize_perform(pserialize_t psz)10144968cbaSchristos pserialize_perform(pserialize_t psz)
10244968cbaSchristos {
10344968cbaSchristos
10444968cbaSchristos KASSERT(!cpu_intr_p());
10544968cbaSchristos KASSERT(!cpu_softintr_p());
10644968cbaSchristos
10744968cbaSchristos if (__predict_false(panicstr != NULL)) {
10844968cbaSchristos return;
10944968cbaSchristos }
11044968cbaSchristos
111412ac21eSmsaitoh if (__predict_false(mp_online == false)) {
112412ac21eSmsaitoh psz_ev_excl.ev_count++;
113412ac21eSmsaitoh return;
114412ac21eSmsaitoh }
115412ac21eSmsaitoh
11644968cbaSchristos /*
117a0c864ecSriastradh * Broadcast a NOP to all CPUs and wait until all of them complete.
11844968cbaSchristos */
119edcef67eSuwe xc_barrier(XC_HIGHPRI);
120ef8a266fSrmind
121d5dccc25Sriastradh mutex_enter(&psz_lock);
122d5dccc25Sriastradh psz_ev_excl.ev_count++;
123d5dccc25Sriastradh mutex_exit(&psz_lock);
12444968cbaSchristos }
12544968cbaSchristos
12644968cbaSchristos int
pserialize_read_enter(void)12744968cbaSchristos pserialize_read_enter(void)
12844968cbaSchristos {
129683f5aa5Sozaki-r int s;
13044968cbaSchristos
131683f5aa5Sozaki-r s = splsoftserial();
132a0c864ecSriastradh curcpu()->ci_psz_read_depth++;
133a0c864ecSriastradh __insn_barrier();
134683f5aa5Sozaki-r return s;
13544968cbaSchristos }
13644968cbaSchristos
13744968cbaSchristos void
pserialize_read_exit(int s)13844968cbaSchristos pserialize_read_exit(int s)
13944968cbaSchristos {
14044968cbaSchristos
141ba7fde6fSriastradh KASSERT(__predict_false(cold) || kpreempt_disabled());
142a0c864ecSriastradh
143a0c864ecSriastradh __insn_barrier();
144a0c864ecSriastradh if (__predict_false(curcpu()->ci_psz_read_depth-- == 0))
145a0c864ecSriastradh panic("mismatching pserialize_read_exit()");
14644968cbaSchristos splx(s);
14744968cbaSchristos }
14844968cbaSchristos
14944968cbaSchristos /*
150683f5aa5Sozaki-r * pserialize_in_read_section:
151683f5aa5Sozaki-r *
152a0c864ecSriastradh * True if the caller is in a pserialize read section. To be used
153a0c864ecSriastradh * only for diagnostic assertions where we want to guarantee the
154a0c864ecSriastradh * condition like:
155683f5aa5Sozaki-r *
156683f5aa5Sozaki-r * KASSERT(pserialize_in_read_section());
157683f5aa5Sozaki-r */
158683f5aa5Sozaki-r bool
pserialize_in_read_section(void)159683f5aa5Sozaki-r pserialize_in_read_section(void)
160683f5aa5Sozaki-r {
161683f5aa5Sozaki-r
162a0c864ecSriastradh return kpreempt_disabled() && curcpu()->ci_psz_read_depth > 0;
163683f5aa5Sozaki-r }
164683f5aa5Sozaki-r
165683f5aa5Sozaki-r /*
166683f5aa5Sozaki-r * pserialize_not_in_read_section:
167683f5aa5Sozaki-r *
168a0c864ecSriastradh * True if the caller is not in a pserialize read section. To be
169a0c864ecSriastradh * used only for diagnostic assertions where we want to guarantee
170a0c864ecSriastradh * the condition like:
171683f5aa5Sozaki-r *
172683f5aa5Sozaki-r * KASSERT(pserialize_not_in_read_section());
173683f5aa5Sozaki-r */
174683f5aa5Sozaki-r bool
pserialize_not_in_read_section(void)175683f5aa5Sozaki-r pserialize_not_in_read_section(void)
176683f5aa5Sozaki-r {
177683f5aa5Sozaki-r bool notin;
178*a355028fSad long pctr;
179683f5aa5Sozaki-r
180*a355028fSad pctr = lwp_pctr();
1815770e8ceSriastradh notin = __predict_true(curcpu()->ci_psz_read_depth == 0);
18283045fafSriastradh
18383045fafSriastradh /*
18483045fafSriastradh * If we had a context switch, we're definitely not in a
18583045fafSriastradh * pserialize read section because pserialize read sections
18683045fafSriastradh * block preemption.
18783045fafSriastradh */
188*a355028fSad if (__predict_false(pctr != lwp_pctr()))
18983045fafSriastradh notin = true;
190683f5aa5Sozaki-r
191683f5aa5Sozaki-r return notin;
192683f5aa5Sozaki-r }
193