From 5915b712cf8cf6a4179eb25f88ba2a980399003d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Tigeot?= Date: Wed, 15 Mar 2017 08:33:02 +0100 Subject: [PATCH] drm/linux: Implement hrtimers This initial implementation is based on callouts and not highly precise. It nevertheless works fine with the drm/i915 driver from Linux 4.7 and will be enough for now. --- sys/conf/files | 1 + sys/dev/drm/drm/Makefile | 1 + sys/dev/drm/include/linux/{sched.h => hrtimer.h} | 76 +++++++++----------- sys/dev/drm/include/linux/interrupt.h | 1 + sys/dev/drm/include/linux/ktime.h | 11 ++- sys/dev/drm/include/linux/sched.h | 19 ++++- sys/dev/drm/linux_hrtimer.c | 89 ++++++++++++++++++++++++ 7 files changed, 150 insertions(+), 48 deletions(-) copy sys/dev/drm/include/linux/{sched.h => hrtimer.h} (58%) create mode 100644 sys/dev/drm/linux_hrtimer.c diff --git a/sys/conf/files b/sys/conf/files index d4b7c38da2..4f2b8fbc18 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2037,6 +2037,7 @@ dev/drm/drm_vma_manager.c optional drm dev/drm/linux_async.c optional drm dev/drm/linux_compat.c optional drm dev/drm/linux_hdmi.c optional drm +dev/drm/linux_hrtimer.c optional drm dev/drm/linux_i2c.c optional drm dev/drm/linux_iomapping.c optional drm dev/drm/linux_list_sort.c optional drm diff --git a/sys/dev/drm/drm/Makefile b/sys/dev/drm/drm/Makefile index 0793519824..4f5cfb7d77 100644 --- a/sys/dev/drm/drm/Makefile +++ b/sys/dev/drm/drm/Makefile @@ -48,6 +48,7 @@ SRCS = \ linux_compat.c \ linux_hdmi.c \ linux_i2c.c \ + linux_hrtimer.c \ linux_iomapping.c \ linux_list_sort.c \ linux_shmem.c \ diff --git a/sys/dev/drm/include/linux/sched.h b/sys/dev/drm/include/linux/hrtimer.h similarity index 58% copy from sys/dev/drm/include/linux/sched.h copy to sys/dev/drm/include/linux/hrtimer.h index 074d9109b6..d18495842c 100644 --- a/sys/dev/drm/include/linux/sched.h +++ b/sys/dev/drm/include/linux/hrtimer.h @@ -1,5 +1,5 @@ -/*- - * Copyright (c) 2015-2017 François Tigeot +/* + * Copyright (c) 2017 François Tigeot * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,55 +23,41 @@ * (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_HRTIMER_H_ +#define _LINUX_HRTIMER_H_ -#ifndef _LINUX_SCHED_H_ -#define _LINUX_SCHED_H_ - -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include -#define TASK_RUNNING 0 -#define TASK_INTERRUPTIBLE 1 -#define TASK_UNINTERRUPTIBLE 2 +enum hrtimer_mode { + HRTIMER_MODE_ABS = 0x0, + HRTIMER_MODE_REL = 0x1, +}; -/* - * schedule_timeout - sleep until timeout - * @timeout: timeout value in jiffies - */ -static inline long -schedule_timeout(signed long timeout) -{ - static int dummy; +enum hrtimer_restart { + HRTIMER_NORESTART, /* Timer is not restarted */ + HRTIMER_RESTART, /* Timer must be restarted */ +}; - if (timeout < 0) { - kprintf("schedule_timeout(): timeout cannot be negative\n"); - return 0; - } +struct hrtimer { + struct callout timer_callout; + clockid_t clock_id; + enum hrtimer_mode ht_mode; + bool active; + enum hrtimer_restart (*function)(struct hrtimer *); + struct lwkt_token timer_token; +}; - tsleep(&dummy, 0, "lstim", timeout); +extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, + enum hrtimer_mode mode); - return 0; -} +extern void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + u64 range_ns, const enum hrtimer_mode mode); -#define TASK_COMM_LEN MAXCOMLEN - -#define signal_pending(lp) CURSIG(lp) - -/* - * local_clock: fast time source, monotonic on the same cpu - */ -static inline uint64_t -local_clock(void) -{ - struct timespec ts; +extern int hrtimer_cancel(struct hrtimer *timer); - getnanouptime(&ts); - return (ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec; -} +extern bool hrtimer_active(const struct hrtimer *timer); -#endif /* _LINUX_SCHED_H_ */ +#endif /* _LINUX_HRTIMER_H_ */ diff --git a/sys/dev/drm/include/linux/interrupt.h b/sys/dev/drm/include/linux/interrupt.h index a4e9f310da..b2a4ea3d9f 100644 --- a/sys/dev/drm/include/linux/interrupt.h +++ b/sys/dev/drm/include/linux/interrupt.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/sys/dev/drm/include/linux/ktime.h b/sys/dev/drm/include/linux/ktime.h index 30458a6024..da3c1b3d1f 100644 --- a/sys/dev/drm/include/linux/ktime.h +++ b/sys/dev/drm/include/linux/ktime.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 François Tigeot + * Copyright (c) 2015-2017 François Tigeot * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,15 @@ union ktime { typedef union ktime ktime_t; +static inline ktime_t +ktime_set(const s64 secs, const unsigned long nsecs) +{ + ktime_t kt; + + kt.tv64 = secs * NSEC_PER_SEC + (s64)nsecs; + return kt; +} + static inline s64 ktime_to_us(const ktime_t kt) { diff --git a/sys/dev/drm/include/linux/sched.h b/sys/dev/drm/include/linux/sched.h index 074d9109b6..d59484b542 100644 --- a/sys/dev/drm/include/linux/sched.h +++ b/sys/dev/drm/include/linux/sched.h @@ -27,14 +27,29 @@ #ifndef _LINUX_SCHED_H_ #define _LINUX_SCHED_H_ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + #include #include #include #include #include -#include - #define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 diff --git a/sys/dev/drm/linux_hrtimer.c b/sys/dev/drm/linux_hrtimer.c new file mode 100644 index 0000000000..da2300bf10 --- /dev/null +++ b/sys/dev/drm/linux_hrtimer.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017 François Tigeot + * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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 +#include + +static inline void +__hrtimer_function(void *arg) +{ + struct hrtimer *timer = arg; + enum hrtimer_restart restart = HRTIMER_RESTART; + + if (timer->function) { + restart = timer->function(timer); + } + + if (restart == HRTIMER_NORESTART) + timer->function = NULL; +} + +void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, + enum hrtimer_mode mode) +{ + BUG_ON(clock_id != CLOCK_MONOTONIC); + + memset(timer, 0, sizeof(struct hrtimer)); + timer->clock_id = clock_id; + timer->ht_mode = mode; + + lwkt_token_init(&timer->timer_token, "timer token"); + callout_init_mp(&(timer)->timer_callout); +} + +void +hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + u64 range_ns, const enum hrtimer_mode mode) +{ + int expire_ticks = tim.tv64 / (NSEC_PER_SEC / hz); + + if (mode == HRTIMER_MODE_ABS) + expire_ticks -= ticks; + + if (expire_ticks <= 0) + expire_ticks = 1; + + lwkt_gettoken(&timer->timer_token); + + timer->active = true; + callout_reset(&timer->timer_callout, + expire_ticks, __hrtimer_function, timer); + + lwkt_reltoken(&timer->timer_token); +} + +int +hrtimer_cancel(struct hrtimer *timer) +{ + return callout_drain(&timer->timer_callout) == 0; +} + +/* Returns non-zero if the timer is already on the queue */ +bool +hrtimer_active(const struct hrtimer *timer) +{ + return callout_pending(&timer->timer_callout); +} -- 2.11.4.GIT