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); +}