git: 6d720cdfe735 - main - linuxkpi: Add `woken_wake_function()` and `wait_woken()`
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 12 May 2025 17:46:47 UTC
The branch main has been updated by dumbbell:
URL: https://cgit.FreeBSD.org/src/commit/?id=6d720cdfe7350d1eed620f1456bbe76ead708c30
commit 6d720cdfe7350d1eed620f1456bbe76ead708c30
Author: Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2024-12-27 21:43:59 +0000
Commit: Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
CommitDate: 2025-05-12 17:08:02 +0000
linuxkpi: Add `woken_wake_function()` and `wait_woken()`
They are used by the i915 DRM driver starting with Linux 6.7.
`(struct wait_queue)->flags` is no longer always zero. I wonder if some
code relied on this...
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48755
---
sys/compat/linuxkpi/common/include/linux/wait.h | 14 ++++--
sys/compat/linuxkpi/common/src/linux_schedule.c | 59 +++++++++++++++++++++++++
2 files changed, 70 insertions(+), 3 deletions(-)
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index bd496793e27e..03ddce2c06f5 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -61,12 +61,14 @@ typedef struct wait_queue_head wait_queue_head_t;
typedef int wait_queue_func_t(wait_queue_t *, unsigned int, int, void *);
+#define WQ_FLAG_WOKEN 0x02
+
/*
* Many API consumers directly reference these fields and those of
* wait_queue_head.
*/
struct wait_queue {
- unsigned int flags; /* always 0 */
+ unsigned int flags;
void *private;
wait_queue_func_t *func;
union {
@@ -87,8 +89,14 @@ struct wait_queue_head {
* This function is referenced by at least one DRM driver, so it may not be
* renamed and furthermore must be the default wait queue callback.
*/
-extern wait_queue_func_t autoremove_wake_function;
-extern wait_queue_func_t default_wake_function;
+wait_queue_func_t autoremove_wake_function;
+wait_queue_func_t default_wake_function;
+wait_queue_func_t woken_wake_function;
+
+long linux_wait_woken(wait_queue_t *wq, unsigned state, long timeout);
+
+#define wait_woken(wq, state, timeout) \
+ linux_wait_woken((wq), (state), (timeout))
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name = { \
diff --git a/sys/compat/linuxkpi/common/src/linux_schedule.c b/sys/compat/linuxkpi/common/src/linux_schedule.c
index 3f3605096d62..c6b7a2ebbd66 100644
--- a/sys/compat/linuxkpi/common/src/linux_schedule.c
+++ b/sys/compat/linuxkpi/common/src/linux_schedule.c
@@ -200,6 +200,65 @@ default_wake_function(wait_queue_t *wq, unsigned int state, int flags,
return (wake_up_task(wq->private, state));
}
+long
+linux_wait_woken(wait_queue_t *wq, unsigned state, long timeout)
+{
+ void *wchan;
+ struct task_struct *task;
+ int ret;
+ int remainder;
+
+ task = current;
+ wchan = wq->private;
+
+ remainder = jiffies + timeout;
+
+ set_task_state(task, state);
+
+ sleepq_lock(wchan);
+ if (!(wq->flags & WQ_FLAG_WOKEN)) {
+ ret = linux_add_to_sleepqueue(wchan, task, "woken",
+ timeout, state);
+ } else {
+ sleepq_release(wchan);
+ ret = 0;
+ }
+
+ set_task_state(task, TASK_RUNNING);
+ wq->flags &= ~WQ_FLAG_WOKEN;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT)
+ return (MAX_SCHEDULE_TIMEOUT);
+
+ /* range check return value */
+ remainder -= jiffies;
+
+ /* range check return value */
+ if (ret == -ERESTARTSYS && remainder < 1)
+ remainder = 1;
+ else if (remainder < 0)
+ remainder = 0;
+ else if (remainder > timeout)
+ remainder = timeout;
+ return (remainder);
+}
+
+int
+woken_wake_function(wait_queue_t *wq, unsigned int state,
+ int flags __unused, void *key __unused)
+{
+ void *wchan;
+
+ wchan = wq->private;
+
+ sleepq_lock(wchan);
+ wq->flags |= WQ_FLAG_WOKEN;
+ sleepq_signal(wchan, SLEEPQ_SLEEP, 0, 0);
+ sleepq_release(wchan);
+
+ return (1);
+}
+
void
linux_init_wait_entry(wait_queue_t *wq, int flags)
{