xref: /dflybsd-src/sys/dev/drm/linux_wait.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
1d658c120SFrançois Tigeot /*
2edbc586dSFrançois Tigeot  * Copyright (c) 2019-2020 François Tigeot <ftigeot@wolfpond.org>
3d658c120SFrançois Tigeot  * All rights reserved.
4d658c120SFrançois Tigeot  *
5d658c120SFrançois Tigeot  * Redistribution and use in source and binary forms, with or without
6d658c120SFrançois Tigeot  * modification, are permitted provided that the following conditions
7d658c120SFrançois Tigeot  * are met:
8d658c120SFrançois Tigeot  * 1. Redistributions of source code must retain the above copyright
9d658c120SFrançois Tigeot  *    notice unmodified, this list of conditions, and the following
10d658c120SFrançois Tigeot  *    disclaimer.
11d658c120SFrançois Tigeot  * 2. Redistributions in binary form must reproduce the above copyright
12d658c120SFrançois Tigeot  *    notice, this list of conditions and the following disclaimer in the
13d658c120SFrançois Tigeot  *    documentation and/or other materials provided with the distribution.
14d658c120SFrançois Tigeot  *
15d658c120SFrançois Tigeot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16d658c120SFrançois Tigeot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17d658c120SFrançois Tigeot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18d658c120SFrançois Tigeot  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19d658c120SFrançois Tigeot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20d658c120SFrançois Tigeot  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21d658c120SFrançois Tigeot  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22d658c120SFrançois Tigeot  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23d658c120SFrançois Tigeot  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24d658c120SFrançois Tigeot  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25d658c120SFrançois Tigeot  */
26d658c120SFrançois Tigeot 
27d658c120SFrançois Tigeot #include <linux/wait.h>
28*3f2dd94aSFrançois Tigeot #include <linux/wait_bit.h>
29d658c120SFrançois Tigeot #include <linux/sched.h>
30d658c120SFrançois Tigeot 
31d658c120SFrançois Tigeot int
default_wake_function(wait_queue_entry_t * q,unsigned mode,int wake_flags,void * key)32*3f2dd94aSFrançois Tigeot default_wake_function(wait_queue_entry_t *q, unsigned mode, int wake_flags, void *key)
33d658c120SFrançois Tigeot {
34d658c120SFrançois Tigeot 	return wake_up_process(q->private);
35d658c120SFrançois Tigeot }
36d658c120SFrançois Tigeot 
37d658c120SFrançois Tigeot int
autoremove_wake_function(wait_queue_entry_t * wait,unsigned mode,int sync,void * key)38*3f2dd94aSFrançois Tigeot autoremove_wake_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
39d658c120SFrançois Tigeot {
40d658c120SFrançois Tigeot 	int ret = default_wake_function(wait, mode, sync, key);
41d658c120SFrançois Tigeot 
42d658c120SFrançois Tigeot 	/* Was the process woken up ? */
43d658c120SFrançois Tigeot 	if (ret)
44*3f2dd94aSFrançois Tigeot 		list_del_init(&wait->entry);
45d658c120SFrançois Tigeot 
46d658c120SFrançois Tigeot 	return ret;
47d658c120SFrançois Tigeot }
48d658c120SFrançois Tigeot 
49d658c120SFrançois Tigeot void
__wake_up_core(wait_queue_head_t * q,int num_to_wake_up)50d658c120SFrançois Tigeot __wake_up_core(wait_queue_head_t *q, int num_to_wake_up)
51d658c120SFrançois Tigeot {
52*3f2dd94aSFrançois Tigeot 	wait_queue_entry_t *curr, *next;
53d658c120SFrançois Tigeot 	int mode = TASK_NORMAL;
54d658c120SFrançois Tigeot 
55*3f2dd94aSFrançois Tigeot 	list_for_each_entry_safe(curr, next, &q->head, entry) {
56d658c120SFrançois Tigeot 		if (curr->func(curr, mode, 0, NULL))
57d658c120SFrançois Tigeot 			num_to_wake_up--;
58d658c120SFrançois Tigeot 
59d658c120SFrançois Tigeot 		if (num_to_wake_up == 0)
60d658c120SFrançois Tigeot 			break;
61d658c120SFrançois Tigeot 	}
62d658c120SFrançois Tigeot }
63edbc586dSFrançois Tigeot 
64edbc586dSFrançois Tigeot void
__wait_event_prefix(wait_queue_head_t * wq,int flags)65edbc586dSFrançois Tigeot __wait_event_prefix(wait_queue_head_t *wq, int flags)
66edbc586dSFrançois Tigeot {
67edbc586dSFrançois Tigeot 	lockmgr(&wq->lock, LK_EXCLUSIVE);
68edbc586dSFrançois Tigeot 	if (flags & PCATCH) {
69edbc586dSFrançois Tigeot 		set_current_state(TASK_INTERRUPTIBLE);
70edbc586dSFrançois Tigeot 	} else {
71edbc586dSFrançois Tigeot 		set_current_state(TASK_UNINTERRUPTIBLE);
72edbc586dSFrançois Tigeot 	}
73edbc586dSFrançois Tigeot 	lockmgr(&wq->lock, LK_RELEASE);
74edbc586dSFrançois Tigeot }
75edbc586dSFrançois Tigeot 
76edbc586dSFrançois Tigeot void
prepare_to_wait(wait_queue_head_t * q,wait_queue_entry_t * wait,int state)77*3f2dd94aSFrançois Tigeot prepare_to_wait(wait_queue_head_t *q, wait_queue_entry_t *wait, int state)
7834949973SFrançois Tigeot {
7934949973SFrançois Tigeot 	lockmgr(&q->lock, LK_EXCLUSIVE);
80*3f2dd94aSFrançois Tigeot 	if (list_empty(&wait->entry))
8134949973SFrançois Tigeot 		__add_wait_queue(q, wait);
8234949973SFrançois Tigeot 	set_current_state(state);
8334949973SFrançois Tigeot 	lockmgr(&q->lock, LK_RELEASE);
8434949973SFrançois Tigeot }
8534949973SFrançois Tigeot 
8634949973SFrançois Tigeot void
finish_wait(wait_queue_head_t * q,wait_queue_entry_t * wait)87*3f2dd94aSFrançois Tigeot finish_wait(wait_queue_head_t *q, wait_queue_entry_t *wait)
88edbc586dSFrançois Tigeot {
89edbc586dSFrançois Tigeot 	set_current_state(TASK_RUNNING);
9034949973SFrançois Tigeot 
9134949973SFrançois Tigeot 	lockmgr(&q->lock, LK_EXCLUSIVE);
92*3f2dd94aSFrançois Tigeot 	if (!list_empty(&wait->entry))
93*3f2dd94aSFrançois Tigeot 		list_del_init(&wait->entry);
9434949973SFrançois Tigeot 	lockmgr(&q->lock, LK_RELEASE);
95edbc586dSFrançois Tigeot }
9667c69cdfSFrançois Tigeot 
9767c69cdfSFrançois Tigeot void
wake_up_bit(void * addr,int bit)9867c69cdfSFrançois Tigeot wake_up_bit(void *addr, int bit)
9967c69cdfSFrançois Tigeot {
10067c69cdfSFrançois Tigeot 	wakeup_one(addr);
10167c69cdfSFrançois Tigeot }
10267c69cdfSFrançois Tigeot 
10367c69cdfSFrançois Tigeot /* Wait for a bit to be cleared or a timeout to expire */
10467c69cdfSFrançois Tigeot int
wait_on_bit_timeout(unsigned long * word,int bit,unsigned mode,unsigned long timeout)10567c69cdfSFrançois Tigeot wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode,
10667c69cdfSFrançois Tigeot 		    unsigned long timeout)
10767c69cdfSFrançois Tigeot {
10867c69cdfSFrançois Tigeot 	int rv, awakened = 0, timeout_expired = 0;
10967c69cdfSFrançois Tigeot 	long start_time;
11067c69cdfSFrançois Tigeot 
11167c69cdfSFrançois Tigeot 	if (!test_bit(bit, word))
11267c69cdfSFrançois Tigeot 		return 0;
11367c69cdfSFrançois Tigeot 
11467c69cdfSFrançois Tigeot 	start_time = ticks;
11567c69cdfSFrançois Tigeot 	set_current_state(mode);
11667c69cdfSFrançois Tigeot 
11767c69cdfSFrançois Tigeot 	do {
11867c69cdfSFrançois Tigeot 		rv = tsleep(word, mode, "lwobt", timeout);
11967c69cdfSFrançois Tigeot 		if (rv == 0)
12067c69cdfSFrançois Tigeot 			awakened = 1;
12167c69cdfSFrançois Tigeot 		if (time_after_eq(start_time, timeout))
12267c69cdfSFrançois Tigeot 			timeout_expired = 1;
12367c69cdfSFrançois Tigeot 	} while (test_bit(bit, word) && !timeout_expired);
12467c69cdfSFrançois Tigeot 
12567c69cdfSFrançois Tigeot 	set_current_state(TASK_RUNNING);
12667c69cdfSFrançois Tigeot 
12767c69cdfSFrançois Tigeot 	if (awakened)
12867c69cdfSFrançois Tigeot 		return 0;
12967c69cdfSFrançois Tigeot 
13067c69cdfSFrançois Tigeot 	return 1;
13167c69cdfSFrançois Tigeot }
132e2a4a6b1SFrançois Tigeot 
__init_waitqueue_head(wait_queue_head_t * q,const char * name,struct lock_class_key * key)133e2a4a6b1SFrançois Tigeot void __init_waitqueue_head(wait_queue_head_t *q,
134e2a4a6b1SFrançois Tigeot 			   const char *name, struct lock_class_key *key)
135e2a4a6b1SFrançois Tigeot {
136e2a4a6b1SFrançois Tigeot 	lockinit(&q->lock, "lwq", 0, 0);
137*3f2dd94aSFrançois Tigeot 	INIT_LIST_HEAD(&q->head);
138*3f2dd94aSFrançois Tigeot }
139*3f2dd94aSFrançois Tigeot 
140*3f2dd94aSFrançois Tigeot int
wait_on_bit(unsigned long * word,int bit,unsigned mode)141*3f2dd94aSFrançois Tigeot wait_on_bit(unsigned long *word, int bit, unsigned mode)
142*3f2dd94aSFrançois Tigeot {
143*3f2dd94aSFrançois Tigeot 	return wait_on_bit_timeout(word, bit, mode, MAX_SCHEDULE_TIMEOUT);
144*3f2dd94aSFrançois Tigeot }
145*3f2dd94aSFrançois Tigeot 
146*3f2dd94aSFrançois Tigeot void
init_wait_entry(struct wait_queue_entry * wq_entry,int flags)147*3f2dd94aSFrançois Tigeot init_wait_entry(struct wait_queue_entry *wq_entry, int flags)
148*3f2dd94aSFrançois Tigeot {
149*3f2dd94aSFrançois Tigeot 	INIT_LIST_HEAD(&wq_entry->entry);
150*3f2dd94aSFrançois Tigeot 	wq_entry->flags = flags;
151*3f2dd94aSFrançois Tigeot 	wq_entry->private = current;
152*3f2dd94aSFrançois Tigeot 	wq_entry->func = autoremove_wake_function;
153e2a4a6b1SFrançois Tigeot }
154