xref: /netbsd-src/sys/kern/subr_pserialize.c (revision a355028fa4f1eaedfae402807330fbc7bf5e9102)
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