From 1e59d1334bde37e93f702e78f96ed3bfcdd88119 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Tigeot?= Date: Wed, 22 Feb 2017 07:06:04 +0100 Subject: [PATCH] drm/linux: Implement tasklets Even though this initial implementation is pretty naive and runs tasklets synchronously, it appears to nevertheless work fine with the drm/i915 driver version from Linux 4.7. --- sys/dev/drm/include/drm/drm_os_linux.h | 1 + sys/dev/drm/include/linux/interrupt.h | 95 ++++++++++++++++++++++++++++++++++ sys/dev/drm/include/linux/spinlock.h | 14 ++++- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 sys/dev/drm/include/linux/interrupt.h diff --git a/sys/dev/drm/include/drm/drm_os_linux.h b/sys/dev/drm/include/drm/drm_os_linux.h index ef147ea896..aa3ac5b00c 100644 --- a/sys/dev/drm/include/drm/drm_os_linux.h +++ b/sys/dev/drm/include/drm/drm_os_linux.h @@ -7,6 +7,7 @@ #include #include #include +#include /* For task queue support */ #include /* Handle the DRM options from kernel config. */ diff --git a/sys/dev/drm/include/linux/interrupt.h b/sys/dev/drm/include/linux/interrupt.h new file mode 100644 index 0000000000..9365539924 --- /dev/null +++ b/sys/dev/drm/include/linux/interrupt.h @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#ifndef _LINUX_INTERRUPT_H_ +#define _LINUX_INTERRUPT_H_ + +#include +#include +#include +#include + +#include + +struct tasklet_struct { + unsigned long state; + void (*func)(unsigned long); + unsigned long data; + struct lock lock; +}; + +enum { + TASKLET_STATE_SCHED, + TASKLET_STATE_RUN +}; + +/* + * TODO: verify these points: + * - tasklets that have the same type cannot be run on multiple processors at the same time + * - tasklets always run on the processor from which they were originally + * submitted + * - when a tasklet is scheduled, its state is set to TASKLET_STATE_SCHED, and the tasklet + * added to a queue + * - during the execution of its function, the tasklet state is set to TASKLET_STATE_RUN + * and the TASKLET_STATE_SCHED state is removed + */ + +/* XXX scheduling and execution should be handled separately */ +static inline void +tasklet_schedule(struct tasklet_struct *t) +{ + set_bit(TASKLET_STATE_SCHED, t->state); + + lockmgr(&t->lock, LK_EXCLUSIVE); + clear_bit(TASKLET_STATE_SCHED, t->state); + + set_bit(TASKLET_STATE_RUN, t->state); + t->func(t->data); + clear_bit(TASKLET_STATE_RUN, t->state); + + lockmgr(&t->lock, LK_RELEASE); +} + +/* This function ensures that the tasklet is not scheduled to run again */ +/* XXX this doesn't kill anything */ +static inline void +tasklet_kill(struct tasklet_struct *t) +{ + lockmgr(&t->lock, LK_EXCLUSIVE); + clear_bit(TASKLET_STATE_SCHED, t->state); + lockmgr(&t->lock, LK_RELEASE); +} + +static inline void +tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data) +{ + lockinit(&t->lock, "ltasklet", 0, LK_CANRECURSE); + t->state = 0; + t->func = func; + t->data = data; +} + +#endif /* _LINUX_INTERRUPT_H_ */ diff --git a/sys/dev/drm/include/linux/spinlock.h b/sys/dev/drm/include/linux/spinlock.h index d1837ae421..c1a3b32889 100644 --- a/sys/dev/drm/include/linux/spinlock.h +++ b/sys/dev/drm/include/linux/spinlock.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 @@ -58,4 +58,16 @@ static inline void spin_unlock_irq(struct lock *lock) #define spin_lock_irqsave(lock, flags) do { flags = 0; spin_lock_irq(lock); } while(0) #define spin_unlock_irqrestore(lock, flags) do { flags = 0; spin_unlock_irq(lock); } while(0) +static inline void +spin_lock_bh(struct lock *lock) +{ + spin_lock_irq(lock); +} + +static inline void +spin_unlock_bh(struct lock *lock) +{ + spin_unlock_irq(lock); +} + #endif /* _LINUX_SPINLOCK_H_ */ -- 2.11.4.GIT