xref: /dflybsd-src/sys/dev/drm/include/linux/completion.h (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
124b50f1aSFrançois Tigeot /*
2647fa573SFrançois Tigeot  * Copyright (c) 2014-2020 François Tigeot <ftigeot@wolfpond.org>
324b50f1aSFrançois Tigeot  * All rights reserved.
424b50f1aSFrançois Tigeot  *
524b50f1aSFrançois Tigeot  * Redistribution and use in source and binary forms, with or without
624b50f1aSFrançois Tigeot  * modification, are permitted provided that the following conditions
724b50f1aSFrançois Tigeot  * are met:
824b50f1aSFrançois Tigeot  * 1. Redistributions of source code must retain the above copyright
924b50f1aSFrançois Tigeot  *    notice unmodified, this list of conditions, and the following
1024b50f1aSFrançois Tigeot  *    disclaimer.
1124b50f1aSFrançois Tigeot  * 2. Redistributions in binary form must reproduce the above copyright
1224b50f1aSFrançois Tigeot  *    notice, this list of conditions and the following disclaimer in the
1324b50f1aSFrançois Tigeot  *    documentation and/or other materials provided with the distribution.
1424b50f1aSFrançois Tigeot  *
1524b50f1aSFrançois Tigeot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1624b50f1aSFrançois Tigeot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1724b50f1aSFrançois Tigeot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1824b50f1aSFrançois Tigeot  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1924b50f1aSFrançois Tigeot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2024b50f1aSFrançois Tigeot  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2124b50f1aSFrançois Tigeot  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2224b50f1aSFrançois Tigeot  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2324b50f1aSFrançois Tigeot  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424b50f1aSFrançois Tigeot  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2524b50f1aSFrançois Tigeot  */
2624b50f1aSFrançois Tigeot #ifndef	_LINUX_COMPLETION_H_
2724b50f1aSFrançois Tigeot #define	_LINUX_COMPLETION_H_
2824b50f1aSFrançois Tigeot 
2924b50f1aSFrançois Tigeot #include <linux/wait.h>
3039cfddd2SFrançois Tigeot #include <linux/errno.h>
3124b50f1aSFrançois Tigeot 
3209f141c4SFrançois Tigeot #include <sys/kernel.h>
3309f141c4SFrançois Tigeot 
3424b50f1aSFrançois Tigeot struct completion {
3524b50f1aSFrançois Tigeot 	unsigned int done;
3624b50f1aSFrançois Tigeot 	wait_queue_head_t wait;
3724b50f1aSFrançois Tigeot };
3824b50f1aSFrançois Tigeot 
3924b50f1aSFrançois Tigeot static inline void
init_completion(struct completion * c)4024b50f1aSFrançois Tigeot init_completion(struct completion *c)
4124b50f1aSFrançois Tigeot {
4224b50f1aSFrançois Tigeot 	c->done = 0;
4324b50f1aSFrançois Tigeot 	init_waitqueue_head(&c->wait);
4424b50f1aSFrançois Tigeot }
4524b50f1aSFrançois Tigeot 
462097fbd4SPeeter Must static inline void
reinit_completion(struct completion * c)472097fbd4SPeeter Must reinit_completion(struct completion *c)
482097fbd4SPeeter Must {
492097fbd4SPeeter Must 	c->done = 0;
502097fbd4SPeeter Must }
512097fbd4SPeeter Must 
5224b50f1aSFrançois Tigeot #define	INIT_COMPLETION(c)	(c.done = 0)
5324b50f1aSFrançois Tigeot 
5444e1bd6eSMatthew Dillon /*
5544e1bd6eSMatthew Dillon  * Completion interlock and wakeup.  Be careful not to execute the wakeup
5644e1bd6eSMatthew Dillon  * from inside the spinlock as this can deadlock if the IPIQ fifo is full.
5744e1bd6eSMatthew Dillon  * (also note that wakeup() is asynchronous anyway, so no point doing that).
5844e1bd6eSMatthew Dillon  */
5924b50f1aSFrançois Tigeot static inline void
complete(struct completion * c)6024b50f1aSFrançois Tigeot complete(struct completion *c)
6124b50f1aSFrançois Tigeot {
6288c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_EXCLUSIVE);
63647fa573SFrançois Tigeot 	if (c->done != UINT_MAX)
6424b50f1aSFrançois Tigeot 		c->done++;
6588c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_RELEASE);
6644e1bd6eSMatthew Dillon 	wakeup_one(&c->wait);
6724b50f1aSFrançois Tigeot }
6824b50f1aSFrançois Tigeot 
6924b50f1aSFrançois Tigeot static inline void
complete_all(struct completion * c)7024b50f1aSFrançois Tigeot complete_all(struct completion *c)
7124b50f1aSFrançois Tigeot {
7288c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_EXCLUSIVE);
73647fa573SFrançois Tigeot 	c->done = UINT_MAX;
7488c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_RELEASE);
7544e1bd6eSMatthew Dillon 	wakeup(&c->wait);
7624b50f1aSFrançois Tigeot }
7724b50f1aSFrançois Tigeot 
7824b50f1aSFrançois Tigeot static inline long
__wait_for_completion_generic(struct completion * c,unsigned long timeout,int flags)7939cfddd2SFrançois Tigeot __wait_for_completion_generic(struct completion *c,
8039cfddd2SFrançois Tigeot 			      unsigned long timeout, int flags)
8124b50f1aSFrançois Tigeot {
8224b50f1aSFrançois Tigeot 	int start_jiffies, elapsed_jiffies, remaining_jiffies;
8324b50f1aSFrançois Tigeot 	bool timeout_expired = false, awakened = false;
8424b50f1aSFrançois Tigeot 	long ret = 1;
8524b50f1aSFrançois Tigeot 
8624b50f1aSFrançois Tigeot 	start_jiffies = ticks;
8724b50f1aSFrançois Tigeot 
8888c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_EXCLUSIVE);
8988c5318eSFrançois Tigeot 	while (c->done == 0 && !timeout_expired) {
9039cfddd2SFrançois Tigeot 		ret = lksleep(&c->wait, &c->wait.lock, flags, "lwfcg", timeout);
9124b50f1aSFrançois Tigeot 		switch(ret) {
9224b50f1aSFrançois Tigeot 		case EWOULDBLOCK:
9324b50f1aSFrançois Tigeot 			timeout_expired = true;
9424b50f1aSFrançois Tigeot 			ret = 0;
9524b50f1aSFrançois Tigeot 			break;
9624b50f1aSFrançois Tigeot 		case ERESTART:
97797013cfSFrançois Tigeot 			ret = -ERESTARTSYS;
9824b50f1aSFrançois Tigeot 			break;
9924b50f1aSFrançois Tigeot 		case 0:
10024b50f1aSFrançois Tigeot 			awakened = true;
10124b50f1aSFrançois Tigeot 			break;
10224b50f1aSFrançois Tigeot 		}
10324b50f1aSFrançois Tigeot 	}
10488c5318eSFrançois Tigeot 	lockmgr(&c->wait.lock, LK_RELEASE);
10524b50f1aSFrançois Tigeot 
10624b50f1aSFrançois Tigeot 	if (awakened) {
10724b50f1aSFrançois Tigeot 		elapsed_jiffies = ticks - start_jiffies;
10824b50f1aSFrançois Tigeot 		remaining_jiffies = timeout - elapsed_jiffies;
10924b50f1aSFrançois Tigeot 		if (remaining_jiffies > 0)
11024b50f1aSFrançois Tigeot 			ret = remaining_jiffies;
11124b50f1aSFrançois Tigeot 	}
11224b50f1aSFrançois Tigeot 
11324b50f1aSFrançois Tigeot 	return ret;
11424b50f1aSFrançois Tigeot }
11524b50f1aSFrançois Tigeot 
116*3f2dd94aSFrançois Tigeot int wait_for_completion_interruptible(struct completion *c);
117*3f2dd94aSFrançois Tigeot 
11839cfddd2SFrançois Tigeot static inline long
wait_for_completion_interruptible_timeout(struct completion * c,unsigned long timeout)11939cfddd2SFrançois Tigeot wait_for_completion_interruptible_timeout(struct completion *c,
12039cfddd2SFrançois Tigeot 		unsigned long timeout)
12139cfddd2SFrançois Tigeot {
12239cfddd2SFrançois Tigeot 	return __wait_for_completion_generic(c, timeout, PCATCH);
12339cfddd2SFrançois Tigeot }
12439cfddd2SFrançois Tigeot 
12539cfddd2SFrançois Tigeot static inline unsigned long
wait_for_completion_timeout(struct completion * c,unsigned long timeout)12639cfddd2SFrançois Tigeot wait_for_completion_timeout(struct completion *c, unsigned long timeout)
12739cfddd2SFrançois Tigeot {
12839cfddd2SFrançois Tigeot 	return __wait_for_completion_generic(c, timeout, 0);
12939cfddd2SFrançois Tigeot }
13039cfddd2SFrançois Tigeot 
131f1e2e235SFrançois Tigeot void wait_for_completion(struct completion *c);
132f1e2e235SFrançois Tigeot 
13339cfddd2SFrançois Tigeot /*
13439cfddd2SFrançois Tigeot  * try_wait_for_completion: try to decrement a completion without blocking
13539cfddd2SFrançois Tigeot  * 			    its thread
13639cfddd2SFrançois Tigeot  * return: false if the completion thread would need to be blocked/queued
13739cfddd2SFrançois Tigeot  * 	   true if a non-blocking decrement was successful
13839cfddd2SFrançois Tigeot  */
13939cfddd2SFrançois Tigeot static inline bool
try_wait_for_completion(struct completion * c)14039cfddd2SFrançois Tigeot try_wait_for_completion(struct completion *c)
14139cfddd2SFrançois Tigeot {
14239cfddd2SFrançois Tigeot 	bool ret = false;
14339cfddd2SFrançois Tigeot 
14439cfddd2SFrançois Tigeot 	/* we can't decrement c->done below 0 */
14539cfddd2SFrançois Tigeot 	if (READ_ONCE(c->done) == 0)
14639cfddd2SFrançois Tigeot 		return false;
14739cfddd2SFrançois Tigeot 
14839cfddd2SFrançois Tigeot 	lockmgr(&c->wait.lock, LK_EXCLUSIVE);
14939cfddd2SFrançois Tigeot 	if (c->done > 0) {
15039cfddd2SFrançois Tigeot 		c->done--;
15139cfddd2SFrançois Tigeot 		ret = true;
15239cfddd2SFrançois Tigeot 	}
15339cfddd2SFrançois Tigeot 	lockmgr(&c->wait.lock, LK_RELEASE);
15439cfddd2SFrançois Tigeot 
15539cfddd2SFrançois Tigeot 	return ret;
15639cfddd2SFrançois Tigeot }
15739cfddd2SFrançois Tigeot 
15824b50f1aSFrançois Tigeot #endif	/* _LINUX_COMPLETION_H_ */
159