1368fd0aaSAndrey Grodzovsky /*
2368fd0aaSAndrey Grodzovsky * Copyright 2019 Advanced Micro Devices, Inc.
3368fd0aaSAndrey Grodzovsky *
4368fd0aaSAndrey Grodzovsky * Permission is hereby granted, free of charge, to any person obtaining a
5368fd0aaSAndrey Grodzovsky * copy of this software and associated documentation files (the "Software"),
6368fd0aaSAndrey Grodzovsky * to deal in the Software without restriction, including without limitation
7368fd0aaSAndrey Grodzovsky * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8368fd0aaSAndrey Grodzovsky * and/or sell copies of the Software, and to permit persons to whom the
9368fd0aaSAndrey Grodzovsky * Software is furnished to do so, subject to the following conditions:
10368fd0aaSAndrey Grodzovsky *
11368fd0aaSAndrey Grodzovsky * The above copyright notice and this permission notice shall be included in
12368fd0aaSAndrey Grodzovsky * all copies or substantial portions of the Software.
13368fd0aaSAndrey Grodzovsky *
14368fd0aaSAndrey Grodzovsky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15368fd0aaSAndrey Grodzovsky * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16368fd0aaSAndrey Grodzovsky * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17368fd0aaSAndrey Grodzovsky * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18368fd0aaSAndrey Grodzovsky * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19368fd0aaSAndrey Grodzovsky * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20368fd0aaSAndrey Grodzovsky * OTHER DEALINGS IN THE SOFTWARE.
21368fd0aaSAndrey Grodzovsky *
22368fd0aaSAndrey Grodzovsky */
23368fd0aaSAndrey Grodzovsky #include <linux/semaphore.h>
24368fd0aaSAndrey Grodzovsky #include <linux/atomic.h>
25368fd0aaSAndrey Grodzovsky
26368fd0aaSAndrey Grodzovsky /*
27*c9155a3cSGeert Uytterhoeven * Reusable 2 PHASE task barrier (rendez-vous point) implementation for N tasks.
289bba6b19SGeert Uytterhoeven * Based on the Little book of semaphores - https://greenteapress.com/wp/semaphores/
29368fd0aaSAndrey Grodzovsky */
30368fd0aaSAndrey Grodzovsky
31368fd0aaSAndrey Grodzovsky
32368fd0aaSAndrey Grodzovsky
33368fd0aaSAndrey Grodzovsky #ifndef DRM_TASK_BARRIER_H_
34368fd0aaSAndrey Grodzovsky #define DRM_TASK_BARRIER_H_
35368fd0aaSAndrey Grodzovsky
36368fd0aaSAndrey Grodzovsky /*
37368fd0aaSAndrey Grodzovsky * Represents an instance of a task barrier.
38368fd0aaSAndrey Grodzovsky */
39368fd0aaSAndrey Grodzovsky struct task_barrier {
40368fd0aaSAndrey Grodzovsky unsigned int n;
41368fd0aaSAndrey Grodzovsky atomic_t count;
42368fd0aaSAndrey Grodzovsky struct semaphore enter_turnstile;
43368fd0aaSAndrey Grodzovsky struct semaphore exit_turnstile;
44368fd0aaSAndrey Grodzovsky };
45368fd0aaSAndrey Grodzovsky
task_barrier_signal_turnstile(struct semaphore * turnstile,unsigned int n)46368fd0aaSAndrey Grodzovsky static inline void task_barrier_signal_turnstile(struct semaphore *turnstile,
47368fd0aaSAndrey Grodzovsky unsigned int n)
48368fd0aaSAndrey Grodzovsky {
49368fd0aaSAndrey Grodzovsky int i;
50368fd0aaSAndrey Grodzovsky
51368fd0aaSAndrey Grodzovsky for (i = 0 ; i < n; i++)
52368fd0aaSAndrey Grodzovsky up(turnstile);
53368fd0aaSAndrey Grodzovsky }
54368fd0aaSAndrey Grodzovsky
task_barrier_init(struct task_barrier * tb)55368fd0aaSAndrey Grodzovsky static inline void task_barrier_init(struct task_barrier *tb)
56368fd0aaSAndrey Grodzovsky {
57368fd0aaSAndrey Grodzovsky tb->n = 0;
58368fd0aaSAndrey Grodzovsky atomic_set(&tb->count, 0);
59368fd0aaSAndrey Grodzovsky sema_init(&tb->enter_turnstile, 0);
60368fd0aaSAndrey Grodzovsky sema_init(&tb->exit_turnstile, 0);
61368fd0aaSAndrey Grodzovsky }
62368fd0aaSAndrey Grodzovsky
task_barrier_add_task(struct task_barrier * tb)63368fd0aaSAndrey Grodzovsky static inline void task_barrier_add_task(struct task_barrier *tb)
64368fd0aaSAndrey Grodzovsky {
65368fd0aaSAndrey Grodzovsky tb->n++;
66368fd0aaSAndrey Grodzovsky }
67368fd0aaSAndrey Grodzovsky
task_barrier_rem_task(struct task_barrier * tb)68368fd0aaSAndrey Grodzovsky static inline void task_barrier_rem_task(struct task_barrier *tb)
69368fd0aaSAndrey Grodzovsky {
70368fd0aaSAndrey Grodzovsky tb->n--;
71368fd0aaSAndrey Grodzovsky }
72368fd0aaSAndrey Grodzovsky
73368fd0aaSAndrey Grodzovsky /*
74368fd0aaSAndrey Grodzovsky * Lines up all the threads BEFORE the critical point.
75368fd0aaSAndrey Grodzovsky *
76368fd0aaSAndrey Grodzovsky * When all thread passed this code the entry barrier is back to locked state.
77368fd0aaSAndrey Grodzovsky */
task_barrier_enter(struct task_barrier * tb)78368fd0aaSAndrey Grodzovsky static inline void task_barrier_enter(struct task_barrier *tb)
79368fd0aaSAndrey Grodzovsky {
80368fd0aaSAndrey Grodzovsky if (atomic_inc_return(&tb->count) == tb->n)
81368fd0aaSAndrey Grodzovsky task_barrier_signal_turnstile(&tb->enter_turnstile, tb->n);
82368fd0aaSAndrey Grodzovsky
83368fd0aaSAndrey Grodzovsky down(&tb->enter_turnstile);
84368fd0aaSAndrey Grodzovsky }
85368fd0aaSAndrey Grodzovsky
86368fd0aaSAndrey Grodzovsky /*
87368fd0aaSAndrey Grodzovsky * Lines up all the threads AFTER the critical point.
88368fd0aaSAndrey Grodzovsky *
89368fd0aaSAndrey Grodzovsky * This function is used to avoid any one thread running ahead if the barrier is
90368fd0aaSAndrey Grodzovsky * used repeatedly .
91368fd0aaSAndrey Grodzovsky */
task_barrier_exit(struct task_barrier * tb)92368fd0aaSAndrey Grodzovsky static inline void task_barrier_exit(struct task_barrier *tb)
93368fd0aaSAndrey Grodzovsky {
94368fd0aaSAndrey Grodzovsky if (atomic_dec_return(&tb->count) == 0)
95368fd0aaSAndrey Grodzovsky task_barrier_signal_turnstile(&tb->exit_turnstile, tb->n);
96368fd0aaSAndrey Grodzovsky
97368fd0aaSAndrey Grodzovsky down(&tb->exit_turnstile);
98368fd0aaSAndrey Grodzovsky }
99368fd0aaSAndrey Grodzovsky
100368fd0aaSAndrey Grodzovsky /* Convinieince function when nothing to be done in between entry and exit */
task_barrier_full(struct task_barrier * tb)101368fd0aaSAndrey Grodzovsky static inline void task_barrier_full(struct task_barrier *tb)
102368fd0aaSAndrey Grodzovsky {
103368fd0aaSAndrey Grodzovsky task_barrier_enter(tb);
104368fd0aaSAndrey Grodzovsky task_barrier_exit(tb);
105368fd0aaSAndrey Grodzovsky }
106368fd0aaSAndrey Grodzovsky
107368fd0aaSAndrey Grodzovsky #endif
108