Module Name: src
Committed By: riastradh
Date: Sun Dec 19 11:23:52 UTC 2021
Modified Files:
src/sys/external/bsd/drm2/include/linux: hrtimer.h
src/sys/external/bsd/drm2/linux: files.drmkms_linux
Added Files:
src/sys/external/bsd/drm2/linux: linux_hrtimer.c
Log Message:
linux compat: Draft hrtimer shims.
(not actually high-resolution, just a wrapper around callout(9))
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/include/linux/hrtimer.h
cvs rdiff -u -r1.30 -r1.31 src/sys/external/bsd/drm2/linux/files.drmkms_linux
cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/linux/linux_hrtimer.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/drm2/include/linux/hrtimer.h
diff -u src/sys/external/bsd/drm2/include/linux/hrtimer.h:1.3 src/sys/external/bsd/drm2/include/linux/hrtimer.h:1.4
--- src/sys/external/bsd/drm2/include/linux/hrtimer.h:1.3 Sun Dec 19 10:38:05 2021
+++ src/sys/external/bsd/drm2/include/linux/hrtimer.h Sun Dec 19 11:23:51 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: hrtimer.h,v 1.3 2021/12/19 10:38:05 riastradh Exp $ */
+/* $NetBSD: hrtimer.h,v 1.4 2021/12/19 11:23:51 riastradh Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -32,9 +32,48 @@
#ifndef _LINUX_HRTIMER_H_
#define _LINUX_HRTIMER_H_
+#include <sys/types.h>
+
+#include <sys/callout.h>
+
+#include <linux/ktime.h>
#include <linux/timer.h>
struct hrtimer {
+ enum hrtimer_restart (*function)(struct hrtimer *);
+
+ struct hrtimer_private *hrt_private;
+};
+
+enum hrtimer_mode {
+ HRTIMER_MODE_ABS,
+ HRTIMER_MODE_REL,
};
+enum hrtimer_restart {
+ HRTIMER_NORESTART,
+ HRTIMER_RESTART,
+};
+
+#define hrtimer_active linux_hrtimer_active
+#define hrtimer_add_expires_ns linux_hrtimer_add_expires_ns
+#define hrtimer_cancel linux_hrtimer_cancel
+#define hrtimer_forward linux_hrtimer_forward
+#define hrtimer_forward_now linux_hrtimer_forward_now
+#define hrtimer_init linux_hrtimer_init
+#define hrtimer_set_expires linux_hrtimer_set_expiresp
+#define hrtimer_start linux_hrtimer_start
+#define hrtimer_start_range_ns linux_hrtimer_start_range_ns
+
+void hrtimer_init(struct hrtimer *, clockid_t, enum hrtimer_mode);
+void hrtimer_set_expires(struct hrtimer *, ktime_t);
+void hrtimer_add_expires_ns(struct hrtimer *, uint64_t);
+void hrtimer_start(struct hrtimer *, ktime_t, enum hrtimer_mode);
+void hrtimer_start_range_ns(struct hrtimer *, ktime_t, uint64_t,
+ enum hrtimer_mode);
+int hrtimer_cancel(struct hrtimer *);
+bool hrtimer_active(struct hrtimer *);
+uint64_t hrtimer_forward(struct hrtimer *, ktime_t, ktime_t);
+uint64_t hrtimer_forward_now(struct hrtimer *, ktime_t);
+
#endif /* _LINUX_HRTIMER_H_ */
Index: src/sys/external/bsd/drm2/linux/files.drmkms_linux
diff -u src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.30 src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.31
--- src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.30 Sun Dec 19 11:21:30 2021
+++ src/sys/external/bsd/drm2/linux/files.drmkms_linux Sun Dec 19 11:23:52 2021
@@ -1,4 +1,4 @@
-# $NetBSD: files.drmkms_linux,v 1.30 2021/12/19 11:21:30 riastradh Exp $
+# $NetBSD: files.drmkms_linux,v 1.31 2021/12/19 11:23:52 riastradh Exp $
define drmkms_linux: i2cexec, i2c_bitbang
@@ -13,6 +13,7 @@ file external/bsd/drm2/linux/linux_dma_f
file external/bsd/drm2/linux/linux_dma_resv.c drmkms_linux
file external/bsd/drm2/linux/linux_dmi.c drmkms_linux
file external/bsd/drm2/linux/linux_firmware.c drmkms_linux
+file external/bsd/drm2/linux/linux_hrtimer.c drmkms_linux
file external/bsd/drm2/linux/linux_i2c.c drmkms_linux
file external/bsd/drm2/linux/linux_idr.c drmkms_linux
file external/bsd/drm2/linux/linux_kmap.c drmkms_linux
Added files:
Index: src/sys/external/bsd/drm2/linux/linux_hrtimer.c
diff -u /dev/null src/sys/external/bsd/drm2/linux/linux_hrtimer.c:1.1
--- /dev/null Sun Dec 19 11:23:52 2021
+++ src/sys/external/bsd/drm2/linux/linux_hrtimer.c Sun Dec 19 11:23:52 2021
@@ -0,0 +1,212 @@
+/* $NetBSD: linux_hrtimer.c,v 1.1 2021/12/19 11:23:52 riastradh Exp $ */
+
+/*-
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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_hrtimer.c,v 1.1 2021/12/19 11:23:52 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/callout.h>
+#include <sys/kmem.h>
+
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+
+struct hrtimer_private {
+ struct callout ch;
+ enum hrtimer_mode mode;
+ ktime_t expires;
+};
+
+static void hrtimer_fire(void *);
+
+void
+hrtimer_init(struct hrtimer *hrt, clockid_t clkid, enum hrtimer_mode mode)
+{
+ struct hrtimer_private *H;
+
+ KASSERTMSG(clkid == CLOCK_MONOTONIC, "clkid %d", clkid);
+
+ H = hrt->hrt_private = kmem_zalloc(sizeof(*H), KM_SLEEP);
+
+ callout_init(&H->ch, CALLOUT_MPSAFE);
+ callout_setfunc(&H->ch, hrtimer_fire, H);
+ H->mode = mode;
+}
+
+static void
+_hrtimer_schedule(struct hrtimer *hrt)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+ int delta;
+
+ switch (H->mode) {
+ case HRTIMER_MODE_ABS:
+ panic("absolute hrtimer NYI");
+ break;
+ case HRTIMER_MODE_REL:
+ delta = ktime_to_ms(H->expires);
+ break;
+ default:
+ panic("invalid hrtimer mode %d", H->mode);
+ }
+ callout_schedule(&H->ch, delta);
+}
+
+static void
+hrtimer_fire(void *cookie)
+{
+ struct hrtimer *hrt = cookie;
+ struct hrtimer_private *H = hrt->hrt_private;
+
+ switch ((*hrt->function)(hrt)) {
+ case HRTIMER_RESTART:
+ _hrtimer_schedule(hrt);
+ break;
+ case HRTIMER_NORESTART:
+ break;
+ }
+
+ callout_ack(&H->ch);
+}
+
+void
+hrtimer_set_expires(struct hrtimer *hrt, ktime_t expires)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+
+ H->expires = expires;
+}
+
+void
+hrtimer_add_expires_ns(struct hrtimer *hrt, uint64_t ns)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+
+ H->expires = ktime_add_ns(H->expires, ns);
+}
+
+void
+hrtimer_start(struct hrtimer *hrt, ktime_t expires, enum hrtimer_mode mode)
+{
+
+ hrtimer_start_range_ns(hrt, expires, 0, mode);
+}
+
+void
+hrtimer_start_range_ns(struct hrtimer *hrt, ktime_t expires, uint64_t range_ns,
+ enum hrtimer_mode mode)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+
+ H->expires = expires;
+ (void)range_ns;
+ H->mode = mode;
+ _hrtimer_schedule(hrt);
+}
+
+int
+hrtimer_cancel(struct hrtimer *hrt)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+ bool active;
+
+ /*
+ * Halt the callout and ascertain whether the hrtimer was
+ * active when we invoked hrtimer_cancel.
+ */
+ if (callout_halt(&H->ch, NULL)) {
+ /* Callout expired, meaning it was active. */
+ active = true;
+ } else {
+ /*
+ * Callout had not yet expired. It will not expire
+ * now, so callout_pending is now stable and
+ * corresponds with whether the hrtimer was active or
+ * not.
+ */
+ active = callout_pending(&H->ch);
+ }
+
+ callout_destroy(&H->ch);
+ kmem_free(H, sizeof(*H));
+
+ explicit_memset(hrt, 0, sizeof(*hrt)); /* paranoia */
+
+ return active;
+}
+
+bool
+hrtimer_active(struct hrtimer *hrt)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+
+ /*
+ * If the callout has been scheduled, but has not yet fired,
+ * then it is pending.
+ *
+ * If the callout has fired, but has not yet reached
+ * callout_ack, then it is invoking.
+ */
+ return callout_pending(&H->ch) || callout_invoking(&H->ch);
+}
+
+uint64_t
+hrtimer_forward(struct hrtimer *hrt, ktime_t now, ktime_t period)
+{
+ struct hrtimer_private *H = hrt->hrt_private;
+ uint64_t now_ms, period_ms, expires_ms, nperiods;
+
+ KASSERT(!callout_pending(&H->ch));
+
+ /*
+ * Can't get better than 10ms precision (or ~1ms if you set
+ * HZ=1000) so not much point in doing this arithmetic at finer
+ * resolution than ms.
+ */
+ now_ms = ktime_to_ms(now);
+ period_ms = ktime_to_ms(period);
+ expires_ms = ktime_to_ms(H->expires);
+
+ /* If it hasn't yet expired, no overruns. */
+ if (now_ms < expires_ms)
+ return 0;
+
+ /* Advance it by as many periods as it should have fired. */
+ /* XXX fenceposts */
+ nperiods = howmany(now_ms - expires_ms, period_ms);
+ H->expires = ktime_add_ns(H->expires, 1000000*nperiods*period_ms);
+
+ return nperiods;
+}
+
+uint64_t
+hrtimer_forward_now(struct hrtimer *hrt, ktime_t period)
+{
+
+ return hrtimer_forward(hrt, ktime_get(), period);
+}