Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 #include <linux/semaphore.h>
0024 #include <linux/atomic.h>
0025 
0026 /*
0027  * Reusable 2 PHASE task barrier (randevouz point) implementation for N tasks.
0028  * Based on the Little book of sempahores - https://greenteapress.com/wp/semaphores/
0029  */
0030 
0031 
0032 
0033 #ifndef DRM_TASK_BARRIER_H_
0034 #define DRM_TASK_BARRIER_H_
0035 
0036 /*
0037  * Represents an instance of a task barrier.
0038  */
0039 struct task_barrier {
0040     unsigned int n;
0041     atomic_t count;
0042     struct semaphore enter_turnstile;
0043     struct semaphore exit_turnstile;
0044 };
0045 
0046 static inline void task_barrier_signal_turnstile(struct semaphore *turnstile,
0047                          unsigned int n)
0048 {
0049     int i;
0050 
0051     for (i = 0 ; i < n; i++)
0052         up(turnstile);
0053 }
0054 
0055 static inline void task_barrier_init(struct task_barrier *tb)
0056 {
0057     tb->n = 0;
0058     atomic_set(&tb->count, 0);
0059     sema_init(&tb->enter_turnstile, 0);
0060     sema_init(&tb->exit_turnstile, 0);
0061 }
0062 
0063 static inline void task_barrier_add_task(struct task_barrier *tb)
0064 {
0065     tb->n++;
0066 }
0067 
0068 static inline void task_barrier_rem_task(struct task_barrier *tb)
0069 {
0070     tb->n--;
0071 }
0072 
0073 /*
0074  * Lines up all the threads BEFORE the critical point.
0075  *
0076  * When all thread passed this code the entry barrier is back to locked state.
0077  */
0078 static inline void task_barrier_enter(struct task_barrier *tb)
0079 {
0080     if (atomic_inc_return(&tb->count) == tb->n)
0081         task_barrier_signal_turnstile(&tb->enter_turnstile, tb->n);
0082 
0083     down(&tb->enter_turnstile);
0084 }
0085 
0086 /*
0087  * Lines up all the threads AFTER the critical point.
0088  *
0089  * This function is used to avoid any one thread running ahead if the barrier is
0090  *  used repeatedly .
0091  */
0092 static inline void task_barrier_exit(struct task_barrier *tb)
0093 {
0094     if (atomic_dec_return(&tb->count) == 0)
0095         task_barrier_signal_turnstile(&tb->exit_turnstile, tb->n);
0096 
0097     down(&tb->exit_turnstile);
0098 }
0099 
0100 /* Convinieince function when nothing to be done in between entry and exit */
0101 static inline void task_barrier_full(struct task_barrier *tb)
0102 {
0103     task_barrier_enter(tb);
0104     task_barrier_exit(tb);
0105 }
0106 
0107 #endif