Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/external/bsd Draft Linux tasklet implementation.
details: https://anonhg.NetBSD.org/src/rev/36a2aeff0838
branches: trunk
changeset: 1027924:36a2aeff0838
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sun Dec 19 01:17:14 2021 +0000
description:
Draft Linux tasklet implementation.
diffstat:
sys/external/bsd/common/conf/files.linux | 3 +-
sys/external/bsd/common/include/linux/tasklet.h | 82 ++++
sys/external/bsd/common/linux/linux_tasklet.c | 471 ++++++++++++++++++++++++
sys/external/bsd/drm2/linux/linux_module.c | 17 +-
4 files changed, 568 insertions(+), 5 deletions(-)
diffs (truncated from 628 to 300 lines):
diff -r 448f50cc6cfb -r 36a2aeff0838 sys/external/bsd/common/conf/files.linux
--- a/sys/external/bsd/common/conf/files.linux Sun Dec 19 01:16:59 2021 +0000
+++ b/sys/external/bsd/common/conf/files.linux Sun Dec 19 01:17:14 2021 +0000
@@ -1,7 +1,8 @@
-# $NetBSD: files.linux,v 1.1 2016/02/25 08:51:54 skrll Exp $
+# $NetBSD: files.linux,v 1.2 2021/12/19 01:17:14 riastradh Exp $
define linux
makeoptions linux CPPFLAGS+="-I$S/external/bsd/common/include"
+file external/bsd/common/linux/linux_tasklet.c linux
file external/bsd/common/linux/linux_work.c linux
diff -r 448f50cc6cfb -r 36a2aeff0838 sys/external/bsd/common/include/linux/tasklet.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/external/bsd/common/include/linux/tasklet.h Sun Dec 19 01:17:14 2021 +0000
@@ -0,0 +1,82 @@
+/* $NetBSD: tasklet.h,v 1.1 2021/12/19 01:17:14 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_TASKLET_H_
+#define _LINUX_TASKLET_H_
+
+/* namespace */
+#define tasklet_disable linux_tasklet_disable
+#define tasklet_disable_nosync linux_tasklet_disable_nosync
+#define tasklet_enable linux_tasklet_enable
+#define tasklet_hi_schedule linux_tasklet_hi_schedule
+#define tasklet_init linux_tasklet_init
+#define tasklet_kill linux_tasklet_kill
+#define tasklet_schedule linux_tasklet_schedule
+#define tasklet_struct linux_tasklet_struct
+
+struct tasklet_struct {
+ SIMPLEQ_ENTRY(tasklet_struct) tl_entry;
+ volatile unsigned tl_state;
+ volatile unsigned tl_disablecount;
+ /* begin Linux API */
+ void (*func)(unsigned long);
+ unsigned long data;
+ /* end Linux API */
+};
+
+#define DEFINE_TASKLET(name, func, data) \
+ struct tasklet_struct name = { \
+ .tl_state = 0, \
+ .tl_disablecount = 0, \
+ .func = (func), \
+ .data = (data), \
+ }
+
+#define DEFINE_TASKLET_DISABLED(name, func, data) \
+ struct tasklet_struct name = { \
+ .tl_state = 0, \
+ .tl_disablecount = 1, \
+ .func = (func), \
+ .data = (data), \
+ }
+
+int linux_tasklets_init(void);
+void linux_tasklets_fini(void);
+
+void tasklet_init(struct tasklet_struct *, void (*)(unsigned long),
+ unsigned long);
+void tasklet_disable(struct tasklet_struct *);
+void tasklet_enable(struct tasklet_struct *);
+void tasklet_schedule(struct tasklet_struct *);
+void tasklet_hi_schedule(struct tasklet_struct *);
+void tasklet_kill(struct tasklet_struct *);
+
+#endif /* _LINUX_TASKLET_H_ */
diff -r 448f50cc6cfb -r 36a2aeff0838 sys/external/bsd/common/linux/linux_tasklet.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/external/bsd/common/linux/linux_tasklet.c Sun Dec 19 01:17:14 2021 +0000
@@ -0,0 +1,471 @@
+/* $NetBSD: linux_tasklet.c,v 1.1 2021/12/19 01:17:14 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_tasklet.c,v 1.1 2021/12/19 01:17:14 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/cpu.h>
+#include <sys/errno.h>
+#include <sys/intr.h>
+#include <sys/lock.h>
+#include <sys/percpu.h>
+#include <sys/queue.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <machine/limits.h>
+
+#include <linux/tasklet.h>
+
+#define TASKLET_SCHEDULED ((unsigned)__BIT(0))
+#define TASKLET_RUNNING ((unsigned)__BIT(1))
+
+struct tasklet_queue {
+ struct percpu *tq_percpu; /* struct tasklet_cpu */
+ void *tq_sih;
+};
+
+SIMPLEQ_HEAD(tasklet_head, tasklet_struct);
+
+struct tasklet_cpu {
+ struct tasklet_head tc_head;
+};
+
+static struct tasklet_queue tasklet_queue __read_mostly;
+static struct tasklet_queue tasklet_hi_queue __read_mostly;
+
+static void tasklet_softintr(void *);
+static int tasklet_queue_init(struct tasklet_queue *, unsigned);
+static void tasklet_queue_fini(struct tasklet_queue *);
+static void tasklet_queue_schedule(struct tasklet_queue *,
+ struct tasklet_struct *);
+static void tasklet_queue_enqueue(struct tasklet_queue *,
+ struct tasklet_struct *);
+
+/*
+ * linux_tasklets_init()
+ *
+ * Initialize the Linux tasklets subsystem. Return 0 on success,
+ * error code on failure.
+ */
+int
+linux_tasklets_init(void)
+{
+ int error;
+
+ error = tasklet_queue_init(&tasklet_queue, SOFTINT_CLOCK);
+ if (error)
+ goto fail0;
+ error = tasklet_queue_init(&tasklet_hi_queue, SOFTINT_SERIAL);
+ if (error)
+ goto fail1;
+
+ /* Success! */
+ return 0;
+
+fail2: __unused
+ tasklet_queue_fini(&tasklet_hi_queue);
+fail1: tasklet_queue_fini(&tasklet_queue);
+fail0: KASSERT(error);
+ return error;
+}
+
+/*
+ * linux_tasklets_fini()
+ *
+ * Finalize the Linux tasklets subsystem. All use of tasklets
+ * must be done.
+ */
+void
+linux_tasklets_fini(void)
+{
+
+ tasklet_queue_fini(&tasklet_hi_queue);
+ tasklet_queue_fini(&tasklet_queue);
+}
+
+/*
+ * tasklet_queue_init(tq, prio)
+ *
+ * Initialize the tasklet queue tq for running tasklets at softint
+ * priority prio (SOFTINT_*).
+ */
+static int
+tasklet_queue_init(struct tasklet_queue *tq, unsigned prio)
+{
+ int error;
+
+ /* Allocate per-CPU memory. percpu_alloc cannot fail. */
+ tq->tq_percpu = percpu_alloc(sizeof(struct tasklet_cpu));
+ KASSERT(tq->tq_percpu != NULL);
+
+ /* Try to establish a softint. softint_establish may fail. */
+ tq->tq_sih = softint_establish(prio|SOFTINT_MPSAFE, &tasklet_softintr,
+ tq);
+ if (tq->tq_sih == NULL) {
+ error = ENOMEM;
+ goto fail1;
+ }
+
+ /* Success! */
+ return 0;
+
+fail2: __unused
+ softint_disestablish(tq->tq_sih);
+ tq->tq_sih = NULL;
+fail1: percpu_free(tq->tq_percpu, sizeof(struct tasklet_cpu));
+ tq->tq_percpu = NULL;
+fail0: __unused
+ KASSERT(error);
+ return error;
+}
+
+/*
+ * tasklet_queue_fini(tq)
+ *
+ * Finalize the tasklet queue tq: free all resources associated
+ * with it.
+ */
+static void
+tasklet_queue_fini(struct tasklet_queue *tq)
+{
+
+ softint_disestablish(tq->tq_sih);
+ tq->tq_sih = NULL;
+ percpu_free(tq->tq_percpu, sizeof(struct tasklet_cpu));
+ tq->tq_percpu = NULL;
+}
+
+/*
+ * tasklet_softintr(cookie)
+ *
+ * Soft interrupt handler: Process queued tasklets on the tasklet
+ * queue passed in as cookie.
+ */
+static void
+tasklet_softintr(void *cookie)
+{
+ struct tasklet_queue *const tq = cookie;
+ struct tasklet_head th = SIMPLEQ_HEAD_INITIALIZER(th);
+ struct tasklet_cpu *tc;
+ int s;
+
+ /*
+ * With all interrupts deferred, transfer the current CPU's
+ * queue of tasklets to a local variable in one swell foop.
+ *
+ * No memory barriers: CPU-local state only.
+ */
+ tc = percpu_getref(tq->tq_percpu);
+ s = splhigh();
+ SIMPLEQ_CONCAT(&th, &tc->tc_head);
+ splx(s);
+ percpu_putref(tq->tq_percpu);
+
+ /* Go through the queue of tasklets we grabbed. */
+ while (!SIMPLEQ_EMPTY(&th)) {
+ struct tasklet_struct *tasklet;
Home |
Main Index |
Thread Index |
Old Index