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