Sun Dec 19 01:37:28 2021 UTC ()
Move Linux SRCU to common.
(riastradh)
diff -r1.3 -r1.4 src/sys/external/bsd/common/conf/files.linux
diff -r0 -r1.1 src/sys/external/bsd/common/include/linux/srcu.h
diff -r0 -r1.1 src/sys/external/bsd/common/linux/linux_srcu.c
diff -r1.2 -r0 src/sys/external/bsd/drm2/include/linux/srcu.h
diff -r1.22 -r1.23 src/sys/external/bsd/drm2/linux/files.drmkms_linux
diff -r1.1 -r0 src/sys/external/bsd/drm2/linux/linux_srcu.c
--- src/sys/external/bsd/common/conf/files.linux 2021/12/19 01:33:17 1.3
+++ src/sys/external/bsd/common/conf/files.linux 2021/12/19 01:37:27 1.4
| @@ -1,9 +1,10 @@ | | | @@ -1,9 +1,10 @@ |
1 | # $NetBSD: files.linux,v 1.3 2021/12/19 01:33:17 riastradh Exp $ | | 1 | # $NetBSD: files.linux,v 1.4 2021/12/19 01:37:27 riastradh Exp $ |
2 | | | 2 | |
3 | define linux | | 3 | define linux |
4 | | | 4 | |
5 | makeoptions linux CPPFLAGS+="-I$S/external/bsd/common/include" | | 5 | makeoptions linux CPPFLAGS+="-I$S/external/bsd/common/include" |
6 | | | 6 | |
7 | file external/bsd/common/linux/linux_rcu.c linux | | 7 | file external/bsd/common/linux/linux_rcu.c linux |
| | | 8 | file external/bsd/common/linux/linux_srcu.c linux |
8 | file external/bsd/common/linux/linux_tasklet.c linux | | 9 | file external/bsd/common/linux/linux_tasklet.c linux |
9 | file external/bsd/common/linux/linux_work.c linux | | 10 | file external/bsd/common/linux/linux_work.c linux |
/* $NetBSD: srcu.h,v 1.1 2021/12/19 01:37:27 riastradh Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Taylor R. Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX_SRCU_H_
#define _LINUX_SRCU_H_
#include <sys/types.h>
#include <sys/condvar.h>
#include <sys/mutex.h>
struct lwp;
struct percpu;
struct srcu {
struct percpu *srcu_percpu; /* struct srcu_cpu */
kmutex_t srcu_lock;
kcondvar_t srcu_cv;
struct lwp *srcu_sync;
int64_t srcu_total;
volatile unsigned srcu_gen;
};
void srcu_init(struct srcu *, const char *);
void srcu_fini(struct srcu *);
int srcu_read_lock(struct srcu *);
void srcu_read_unlock(struct srcu *, int);
void synchronize_srcu(struct srcu *);
#endif /* _LINUX_SRCU_H_ */
/* $NetBSD: linux_srcu.c,v 1.1 2021/12/19 01:37:27 riastradh Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Taylor R. Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_srcu.c,v 1.1 2021/12/19 01:37:27 riastradh Exp $");
/*
* SRCU: Sleepable RCU
*
* (This is not exactly SRCU as Linux implements it; it is my
* approximation of the semantics I think we need.)
*
* For each srcu context, representing a related set of read
* sections, on each CPU we store two counts of numbers of
* readers in two epochs: active readers and draining readers.
*
* All new srcu read sections get counted in the active epoch.
* When there's no synchronize_srcu in progress, the draining
* epoch has zero readers. When a thread calls synchronize_srcu,
* which must be serialized by the caller, it it swaps the sense
* of the epochs, issues an xcall to collect a global count of the
* number of readers in the now-draining epoch, and waits for the
* remainder to complete.
*
* This is basically NetBSD localcount(9), but without the
* restriction that the caller of localcount_drain must guarantee
* no new readers -- srcu uses two counts per CPU instead of one
* like localcount(9), and synchronize_srcu just waits for all
* existing readers to drain while new oness count toward a new
* epoch.
*/
#include <sys/types.h>
#include <sys/condvar.h>
#include <sys/mutex.h>
#include <sys/percpu.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/xcall.h>
#include <linux/srcu.h>
struct srcu_cpu {
int64_t src_count[2];
};
/*
* srcu_init(srcu, name)
*
* Initialize the srcu state with the specified name. Caller must
* call srcu_fini when done.
*
* name should be no longer than 8 characters; longer will be
* truncated.
*
* May sleep.
*/
void
srcu_init(struct srcu *srcu, const char *name)
{
ASSERT_SLEEPABLE();
srcu->srcu_percpu = percpu_alloc(sizeof(struct srcu_cpu));
mutex_init(&srcu->srcu_lock, MUTEX_DEFAULT, IPL_VM);
cv_init(&srcu->srcu_cv, name);
srcu->srcu_sync = NULL;
srcu->srcu_total = 0;
srcu->srcu_gen = 0;
}
/*
* srcu_fini(srcu)
*
* Finalize an srcu state, which must not be in use right now. If
* any srcu read sections might be active, caller must wait for
* them to complete with synchronize_srcu.
*
* May sleep.
*/
void
srcu_fini(struct srcu *srcu)
{
ASSERT_SLEEPABLE();
KASSERTMSG((srcu->srcu_sync == NULL),
"srcu_fini in lwp %p while synchronize_srcu running in lwp %p",
curlwp, srcu->srcu_sync);
cv_destroy(&srcu->srcu_cv);
mutex_destroy(&srcu->srcu_lock);
percpu_free(srcu->srcu_percpu, sizeof(struct srcu_cpu));
}
/*
* srcu_adjust(srcu, gen, delta)
*
* Internal subroutine: Add delta to the local CPU's count of
* readers in the generation gen.
*
* Never sleeps.
*/
static void
srcu_adjust(struct srcu *srcu, unsigned gen, int delta)
{
struct srcu_cpu *cpu;
unsigned epoch = gen & 1; /* active epoch */
cpu = percpu_getref(srcu->srcu_percpu);
cpu->src_count[epoch] += delta;
percpu_putref(srcu->srcu_percpu);
}
/*
* srcu_read_lock(srcu)
*
* Enter an srcu read section and return a ticket for it. Any
* subsequent synchronize_srcu will wait until this thread calls
* srcu_read_unlock(srcu, ticket).
*
* Never sleeps.
*/
int
srcu_read_lock(struct srcu *srcu)
{
unsigned gen;
/*
* Prevent xcall while we fetch the generation and adjust the
* count.
*/
kpreempt_disable();
gen = srcu->srcu_gen;
/* Fetch the generation once before incrementing the count. */
__insn_barrier();
srcu_adjust(srcu, gen, +1);
kpreempt_enable();
/*
* Increment the count in our generation before doing anything
* else on this CPU.
*
* No stronger, inter-CPU memory barrier is needed: if there is
* a concurrent synchronize_srcu, it will issue an xcall that
* functions as a stronger memory barrier.
*/
__insn_barrier();
return gen;
}
/*
* srcu_read_unlock(srcu, ticket)
*
* Exit an srcu read section started with srcu_read_lock returning
* ticket. If there is a pending synchronize_srcu and we might be
* the last reader, notify it.
*
* Never sleeps.
*/
void
srcu_read_unlock(struct srcu *srcu, int ticket)
{
unsigned gen = ticket;
/*
* Make sure all side effects have completed on this CPU before
* decrementing the count.
*
* No stronger, inter-CPU memory barrier is needed: if there is
* a concurrent synchronize_srcu, it will issue an xcall that
* functions as a stronger memory barrier.
*/
__insn_barrier();
/*
* Prevent xcall while we determine whether we need to notify a
* sync and decrement the count in our generation.
*/
kpreempt_disable();
if (__predict_true(gen == srcu->srcu_gen)) {
/*
* Fast path: just decrement the local count. If a
* sync has begun and incremented gen after we observed
* it, it will issue an xcall that will run after this
* kpreempt_disable section to collect our local count.
*/
srcu_adjust(srcu, gen, -1);
} else {
/*
* Slow path: decrement the total count, and if it goes
* to zero, notify the sync in progress. The xcall may
* have already run, or it may have yet to run; since
* we can't tell which, we must contribute to the
* global count, not to our local count.
*/
mutex_spin_enter(&srcu->srcu_lock);
KASSERT(srcu->srcu_sync != NULL);
if (--srcu->srcu_total == 0)
cv_broadcast(&srcu->srcu_cv);
mutex_spin_exit(&srcu->srcu_lock);
}
kpreempt_enable();
}
/*
* synchronize_srcu_xc(a, b)
*
* Cross-call function for synchronize_srcu: a is the struct srcu
* pointer; b is ignored. Transfer the local count of srcu
* readers on this CPU in the inactive epoch to the global count
* under the srcu sync lock.
*/
static void
synchronize_srcu_xc(void *a, void *b)
{
struct srcu *srcu = a;
struct srcu_cpu *cpu;
unsigned gen, epoch;
uint64_t local;
/* Operate under the sync lock. Blocks preemption as side effect. */
mutex_spin_enter(&srcu->srcu_lock);
gen = srcu->srcu_gen; /* active generation */
epoch = 1 ^ (gen & 1); /* draining epoch */
/* Transfer the local count to the global count. */
cpu = percpu_getref(srcu->srcu_percpu);
local = cpu->src_count[epoch];
srcu->srcu_total += local;
cpu->src_count[epoch] -= local; /* i.e., cpu->src_count[epoch] = 0 */
KASSERT(cpu->src_count[epoch] == 0);
percpu_putref(srcu->srcu_percpu);
mutex_spin_exit(&srcu->srcu_lock);
}
/*
* synchronize_srcu(srcu)
*
* Wait for all srcu readers on all CPUs that may have begun
* before sychronize_srcu to complete.
*
* May sleep. (Practically guaranteed to sleep!)
*/
void
synchronize_srcu(struct srcu *srcu)
{
ASSERT_SLEEPABLE();
/* Start a sync, and advance the active generation. */
mutex_spin_enter(&srcu->srcu_lock);
while (srcu->srcu_sync != NULL)
cv_wait(&srcu->srcu_cv, &srcu->srcu_lock);
KASSERT(srcu->srcu_total == 0);
srcu->srcu_sync = curlwp;
srcu->srcu_gen++;
mutex_spin_exit(&srcu->srcu_lock);
/*
* Wait for all CPUs to witness the change to the active
* generation, and collect their local counts in the draining
* epoch into the global count.
*/
xc_wait(xc_broadcast(0, synchronize_srcu_xc, srcu, NULL));
/*
* Wait for the global count of users in the draining epoch to
* drain to zero.
*/
mutex_spin_enter(&srcu->srcu_lock);
while (srcu->srcu_total != 0)
cv_wait(&srcu->srcu_cv, &srcu->srcu_lock);
srcu->srcu_sync = NULL;
cv_broadcast(&srcu->srcu_cv);
mutex_spin_exit(&srcu->srcu_lock);
}
--- src/sys/external/bsd/drm2/linux/files.drmkms_linux 2021/12/19 01:34:57 1.22
+++ src/sys/external/bsd/drm2/linux/files.drmkms_linux 2021/12/19 01:37:28 1.23
| @@ -1,23 +1,22 @@ | | | @@ -1,23 +1,22 @@ |
1 | # $NetBSD: files.drmkms_linux,v 1.22 2021/12/19 01:34:57 riastradh Exp $ | | 1 | # $NetBSD: files.drmkms_linux,v 1.23 2021/12/19 01:37:28 riastradh Exp $ |
2 | | | 2 | |
3 | define drmkms_linux: i2cexec, i2c_bitbang | | 3 | define drmkms_linux: i2cexec, i2c_bitbang |
4 | | | 4 | |
5 | makeoptions drmkms_linux CPPFLAGS+="-I$S/external/bsd/common/include" | | 5 | makeoptions drmkms_linux CPPFLAGS+="-I$S/external/bsd/common/include" |
6 | makeoptions drmkms_linux CPPFLAGS+="-I$S/external/bsd/drm2/include" | | 6 | makeoptions drmkms_linux CPPFLAGS+="-I$S/external/bsd/drm2/include" |
7 | | | 7 | |
8 | file external/bsd/drm2/linux/linux_atomic64.c drmkms_linux | | 8 | file external/bsd/drm2/linux/linux_atomic64.c drmkms_linux |
9 | file external/bsd/drm2/linux/linux_dma_buf.c drmkms_linux | | 9 | file external/bsd/drm2/linux/linux_dma_buf.c drmkms_linux |
10 | file external/bsd/drm2/linux/linux_dma_fence.c drmkms_linux | | 10 | file external/bsd/drm2/linux/linux_dma_fence.c drmkms_linux |
11 | file external/bsd/drm2/linux/linux_dmi.c drmkms_linux | | 11 | file external/bsd/drm2/linux/linux_dmi.c drmkms_linux |
12 | file external/bsd/drm2/linux/linux_i2c.c drmkms_linux | | 12 | file external/bsd/drm2/linux/linux_i2c.c drmkms_linux |
13 | file external/bsd/drm2/linux/linux_idr.c drmkms_linux | | 13 | file external/bsd/drm2/linux/linux_idr.c drmkms_linux |
14 | file external/bsd/drm2/linux/linux_kmap.c drmkms_linux | | 14 | file external/bsd/drm2/linux/linux_kmap.c drmkms_linux |
15 | file external/bsd/drm2/linux/linux_list_sort.c drmkms_linux | | 15 | file external/bsd/drm2/linux/linux_list_sort.c drmkms_linux |
16 | file external/bsd/drm2/linux/linux_module.c drmkms_linux | | 16 | file external/bsd/drm2/linux/linux_module.c drmkms_linux |
17 | file external/bsd/drm2/linux/linux_pci.c drmkms_linux | | 17 | file external/bsd/drm2/linux/linux_pci.c drmkms_linux |
18 | file external/bsd/drm2/linux/linux_reservation.c drmkms_linux | | 18 | file external/bsd/drm2/linux/linux_reservation.c drmkms_linux |
19 | file external/bsd/drm2/linux/linux_srcu.c drmkms_linux | | | |
20 | file external/bsd/drm2/linux/linux_stop_machine.c drmkms_linux | | 19 | file external/bsd/drm2/linux/linux_stop_machine.c drmkms_linux |
21 | file external/bsd/drm2/linux/linux_wait_bit.c drmkms_linux | | 20 | file external/bsd/drm2/linux/linux_wait_bit.c drmkms_linux |
22 | file external/bsd/drm2/linux/linux_writecomb.c drmkms_linux | | 21 | file external/bsd/drm2/linux/linux_writecomb.c drmkms_linux |
23 | file external/bsd/drm2/linux/linux_ww_mutex.c drmkms_linux | | 22 | file external/bsd/drm2/linux/linux_ww_mutex.c drmkms_linux |