• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 #ifndef __OAL_ATOMIC_H__
19 #define __OAL_ATOMIC_H__
20 
21 /* ****************************************************************************
22   1 其他头文件包含
23 **************************************************************************** */
24 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
25 #include "hi_types.h"
26 #include <asm/atomic.h>
27 #ifndef HAVE_PCLINT_CHECK
28 #include <linux/bitops.h>
29 #endif
30 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
31 #include <los_hwi.h>
32 #endif
33 
34 #ifdef __cplusplus
35 #if __cplusplus
36 extern "C" {
37 #endif
38 #endif
39 
40 /* ****************************************************************************
41   2 STRUCT定义
42 **************************************************************************** */
43 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
44 
45 typedef atomic_t        oal_atomic;
46 typedef unsigned long   oal_bitops;
47 
48 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
49 
50 typedef struct {
51     volatile int counter;
52 } oal_atomic;
53 typedef unsigned long oal_bitops;
54 
55 #endif
56 
57 /* ****************************************************************************
58   3 枚举定义
59 **************************************************************************** */
60 /* ****************************************************************************
61   4 全局变量声明
62 **************************************************************************** */
63 /* ****************************************************************************
64   5 消息头定义
65 **************************************************************************** */
66 /* ****************************************************************************
67   6 消息定义
68 **************************************************************************** */
69 /* ****************************************************************************
70   7 宏定义
71 **************************************************************************** */
72 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
73 
74 #define oal_atomic_inc_return atomic_inc_return
75 #define oal_bit_atomic_for_each_set(nr, p_addr, size) for_each_set_bit(nr, p_addr, size)
76 
77 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
78 
79 #define BITS_PER_LONG       32
80 #define IS_BIT_SET(nr)        (1UL << ((nr) % BITS_PER_LONG))
81 #define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)
82 #define BITOP_WORD(nr)      ((nr) / BITS_PER_LONG)
83 #define OAL_ATOMIC_INIT(i)  { (i) }
84 
85 #define oal_atomic_inc_return(v) (oal_atomic_add_return(1, v))
86 #define oal_atomic_dec_return(v) (oal_atomic_sub_return(1, v))
87 #define oal_atomic_sub_and_test(i, v) (oal_atomic_sub_return(i, v) == 0)
88 
89 #define oal_bit_atomic_for_each_set(bit, addr,size) \
90             for ((bit) = find_next_bit((addr), (size), 0); \
91             (bit) < (size); \
92             (bit) = (hi_s32)find_next_bit((addr), (size), (bit) + 1))
93 
94 #endif
95 
96 /* ****************************************************************************
97   8 UNION定义
98 **************************************************************************** */
99 /* ****************************************************************************
100   9 OTHERS定义
101 **************************************************************************** */
102 /* ****************************************************************************
103   10 函数声明
104 **************************************************************************** */
105 #if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
106 #if __LINUX_ARM_ARCH__ >= 6
107 
108 /*
109  * ARMv6 UP and SMP safe atomic ops.  We use load exclusive and
110  * store exclusive to ensure that these are atomic.  We may loop
111  * to ensure that the update happens.
112  */
atomic_add(int i,oal_atomic * v)113 static inline void atomic_add(int i, oal_atomic *v)
114 {
115     unsigned long tmp;
116     int result;
117 
118     __asm__ __volatile__("@ atomic_add\n"
119         "1: ldrex   %0, [%2]\n"
120         "   add %0, %0, %3\n"
121         "   strex   %1, %0, [%2]\n"
122         "   teq %1, #0\n"
123         "   bne 1b"
124         : "=&r"(result), "=&r"(tmp)
125         : "r"(&v->counter), "Ir"(i)
126         : "cc");
127 }
128 
atomic_add_return(int i,oal_atomic * v)129 static inline int atomic_add_return(int i, oal_atomic *v)
130 {
131     unsigned long tmp;
132     int result;
133 
134     smp_mb();
135 
136     __asm__ __volatile__("@ atomic_add_return\n"
137         "1: ldrex   %0, [%2]\n"
138         "   add %0, %0, %3\n"
139         "   strex   %1, %0, [%2]\n"
140         "   teq %1, #0\n"
141         "   bne 1b"
142         : "=&r"(result), "=&r"(tmp)
143         : "r"(&v->counter), "Ir"(i)
144         : "cc");
145 
146     smp_mb();
147 
148     return result;
149 }
150 
atomic_sub(int i,oal_atomic * v)151 static inline void atomic_sub(int i, oal_atomic *v)
152 {
153     unsigned long tmp;
154     int result;
155 
156     __asm__ __volatile__("@ atomic_sub\n"
157         "1: ldrex   %0, [%2]\n"
158         "   sub %0, %0, %3\n"
159         "   strex   %1, %0, [%2]\n"
160         "   teq %1, #0\n"
161         "   bne 1b"
162         : "=&r"(result), "=&r"(tmp)
163         : "r"(&v->counter), "Ir"(i)
164         : "cc");
165 }
166 
atomic_sub_return(int i,oal_atomic * v)167 static inline int atomic_sub_return(int i, oal_atomic *v)
168 {
169     unsigned long tmp;
170     int result;
171 
172     smp_mb();
173 
174     __asm__ __volatile__("@ atomic_sub_return\n"
175         "1: ldrex   %0, [%2]\n"
176         "   sub %0, %0, %3\n"
177         "   strex   %1, %0, [%2]\n"
178         "   teq %1, #0\n"
179         "   bne 1b"
180         : "=&r"(result), "=&r"(tmp)
181         : "r"(&v->counter), "Ir"(i)
182         : "cc");
183 
184     smp_mb();
185 
186     return result;
187 }
188 
189 #else /* ARM_ARCH_6 */
190 
191 #ifdef CONFIG_SMP
192 #error SMP not supported on pre-ARMv6 CPUs
193 #endif
194 
oal_atomic_add_return(int i,oal_atomic * v)195 static inline int oal_atomic_add_return(int i, oal_atomic *v)
196 {
197     UINTPTR int_save;
198     int val;
199 
200     int_save = LOS_IntLock();
201     val = v->counter;
202     v->counter = val += i;
203     (VOID)LOS_IntRestore(int_save);
204 
205     return val;
206 }
207 #define oal_atomic_add(i, v) (void)oal_atomic_add_return(i, v)
208 
oal_atomic_sub_return(int i,oal_atomic * v)209 static inline int oal_atomic_sub_return(int i, oal_atomic *v)
210 {
211     UINTPTR int_save;
212     int val;
213 
214     int_save = LOS_IntLock();
215     val = v->counter;
216     v->counter = val -= i;
217     (VOID)LOS_IntRestore(int_save);
218 
219     return val;
220 }
221 #define oal_atomic_sub(i, v) (void)oal_atomic_sub_return(i, v)
222 
223 #endif /* end of __LINUX_ARM_ARCH__ */
224 
__ffs(unsigned long word)225 static inline unsigned long __ffs(unsigned long word)
226 {
227     unsigned long num = 0;
228 
229 #if BITS_PER_LONG == 64
230     if ((word & 0xffffffff) == 0) {
231         num += 32;   /* num add 32 */
232         word >>= 32; /* word right shift 32 */
233     }
234 #endif
235     if ((word & 0xffff) == 0) {
236         num += 16;   /* num add 16 */
237         word >>= 16; /* word right shift 16 */
238     }
239     if ((word & 0xff) == 0) {
240         num += 8;   /* num add 8 */
241         word >>= 8; /* word right shift 8 */
242     }
243     if ((word & 0xf) == 0) {
244         num += 4;   /* num add 4 */
245         word >>= 4; /* word right shift 4 */
246     }
247     if ((word & 0x3) == 0) {
248         num += 2;   /* num add 2 */
249         word >>= 2; /* word right shift 2 */
250     }
251     if ((word & 0x1) == 0)
252         num += 1;
253     return num;
254 }
255 
256 
find_next_bit(const oal_bitops * addr,oal_bitops size,oal_bitops offset)257 static inline oal_bitops find_next_bit(const oal_bitops *addr, oal_bitops size, oal_bitops offset)
258 {
259     const oal_bitops *p = addr + BITOP_WORD(offset);
260     oal_bitops result = offset & ~(BITS_PER_LONG - 1);
261     oal_bitops tmp;
262 
263     if (offset >= size) {
264         return size;
265     }
266     size -= result;
267     offset %= BITS_PER_LONG;
268     if (offset) {
269         tmp = *(p++);
270         tmp &= (~0UL << offset);
271         if (size < BITS_PER_LONG) {
272             goto found_first;
273         }
274         if (tmp) {
275             goto found_middle;
276         }
277         size -= BITS_PER_LONG;
278         result += BITS_PER_LONG;
279     }
280     while (size & ~(BITS_PER_LONG - 1)) {
281         if ((tmp = *(p++))) {
282             goto found_middle;
283         }
284         result += BITS_PER_LONG;
285         size -= BITS_PER_LONG;
286     }
287     if (!size) {
288         return result;
289     }
290     tmp = *p;
291 
292 found_first:
293     tmp &= (~0UL >> (BITS_PER_LONG - size));
294     if (tmp == 0UL) {         /* Are any bits set? */
295         return result + size; /* Nope. */
296     }
297 found_middle:
298     return result + __ffs(tmp);
299 }
300 
301 #endif /* end of _PRE_OS_VERSION_LITEOS */
302 
303 
304 /* ****************************************************************************
305  功能描述  : 读取原子变量的值
306  输入参数  : *p_vector: 需要进行原子操作的原子变量地址
307  输出参数  : 无
308  返 回 值  :
309 **************************************************************************** */
oal_atomic_read(const oal_atomic * p_vector)310 static inline hi_s32 oal_atomic_read(const oal_atomic *p_vector)
311 {
312 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
313     return atomic_read(p_vector);
314 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
315     return p_vector->counter;
316 #endif
317 }
318 
319 /* ****************************************************************************
320  功能描述  : 原子地设置原子变量p_vector值为ul_val
321  输入参数  : p_vector: 需要进行原子操作的原子变量地址
322              l_val  : 需要被设置成的值
323  输出参数  : 无
324  返 回 值  : hi_void
325 **************************************************************************** */
oal_atomic_set(oal_atomic * p_vector,hi_s32 l_val)326 static inline hi_void oal_atomic_set(oal_atomic *p_vector, hi_s32 l_val)
327 {
328 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
329     atomic_set(p_vector, l_val);
330 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
331     p_vector->counter = l_val;
332 #endif
333 }
334 
335 /* ****************************************************************************
336  功能描述  : 原子的给入参减1,
337  输入参数  : *p_vector: 需要进行原子操作的原子变量地址
338  输出参数  : 无
339  返 回 值  :
340 **************************************************************************** */
oal_atomic_dec(oal_atomic * p_vector)341 static inline hi_void oal_atomic_dec(oal_atomic *p_vector)
342 {
343 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
344     atomic_dec(p_vector);
345 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
346     oal_atomic_sub(1, p_vector);
347 #endif
348 }
349 
350 /* ****************************************************************************
351  功能描述  : 原子的给如参加一
352  输入参数  : *p_vector: 需要进行原子操作的原子变量地址
353  输出参数  : 无
354  返 回 值  :
355 **************************************************************************** */
oal_atomic_inc(oal_atomic * p_vector)356 static inline hi_void oal_atomic_inc(oal_atomic *p_vector)
357 {
358 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
359     atomic_inc(p_vector);
360 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
361     oal_atomic_add(1, p_vector);
362 #endif
363 }
364 
365 /* ****************************************************************************
366  功能描述  : 原子递增后检查结果是否为0
367  输入参数  : *p_vector: 需要进行原子操作的原子变量地址
368  输出参数  : 无
369  返 回 值  :
370 **************************************************************************** */
oal_atomic_inc_and_test(oal_atomic * p_vector)371 static inline hi_s32 oal_atomic_inc_and_test(oal_atomic *p_vector)
372 {
373 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
374     return atomic_inc_and_test(p_vector);
375 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
376     return (oal_atomic_add_return(1, p_vector) == 0);
377 #endif
378 }
379 
380 /* ****************************************************************************
381  功能描述  : 原子递减后检查结果是否为0
382  输入参数  : *p_vector: 需要进行原子操作的原子变量地址
383  输出参数  : 无
384  返 回 值  :
385 **************************************************************************** */
oal_atomic_dec_and_test(oal_atomic * p_vector)386 static inline hi_s32 oal_atomic_dec_and_test(oal_atomic *p_vector)
387 {
388 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
389     return atomic_dec_and_test(p_vector);
390 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
391     return (oal_atomic_sub_return(1, p_vector) == 0);
392 #endif
393 }
394 
oal_bit_atomic_set(hi_s32 nr,HI_VOLATILE oal_bitops * p_addr)395 static inline hi_void oal_bit_atomic_set(hi_s32 nr, HI_VOLATILE oal_bitops *p_addr)
396 {
397 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
398     set_bit(nr, p_addr);
399 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
400     UINTPTR int_save;
401     int_save = LOS_IntLock();
402 
403     const oal_bitops mask = IS_BIT_SET(nr);
404     oal_bitops *p = ((oal_bitops *)p_addr) + BIT_WORD(nr);
405     *p |= mask;
406 
407     (VOID)LOS_IntRestore(int_save);
408 #endif
409 }
410 
oal_bit_atomic_test(hi_s32 nr,HI_VOLATILE const oal_bitops * p_addr)411 static inline hi_s32 oal_bit_atomic_test(hi_s32 nr, HI_VOLATILE const oal_bitops *p_addr)
412 {
413 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
414     return test_bit(nr, p_addr);
415 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
416     return (1UL & (p_addr[BIT_WORD(nr)] >> ((hi_u32)nr & (BITS_PER_LONG - 1))));
417 #endif
418 }
419 
420 /* ****************************************************************************
421  功能描述  : 原子的对某个位进行置1操作,并返回该位置的旧值。
422  输入参数  : nr: 需要设置的位
423              p_addr需要置位的变量地址
424  输出参数  :
425  返 回 值  : 返回原来bit位的值
426 **************************************************************************** */
oal_bit_atomic_test_and_set(hi_s32 nr,HI_VOLATILE oal_bitops * p_addr)427 static inline oal_bitops oal_bit_atomic_test_and_set(hi_s32 nr, HI_VOLATILE oal_bitops *p_addr)
428 {
429 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
430     return test_and_set_bit(nr, p_addr);
431 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
432     UINTPTR int_save;
433     int_save = LOS_IntLock();
434 
435     oal_bitops mask = IS_BIT_SET(nr);
436     oal_bitops *p = ((oal_bitops *)p_addr) + BIT_WORD(nr);
437     oal_bitops old = *p;
438     *p = old | mask;
439 
440     (VOID)LOS_IntRestore(int_save);
441     return ((old & mask) != 0);
442 #endif
443 }
444 
oal_bit_atomic_test_and_clear(hi_u32 nr,HI_VOLATILE oal_bitops * p_addr)445 static inline oal_bitops oal_bit_atomic_test_and_clear(hi_u32 nr, HI_VOLATILE oal_bitops *p_addr)
446 {
447 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
448     return (oal_bitops)test_and_clear_bit(nr, p_addr);
449 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
450     UINTPTR int_save;
451     int_save = LOS_IntLock();
452 
453     oal_bitops mask = IS_BIT_SET(nr);
454     oal_bitops *p = ((oal_bitops *)p_addr) + BIT_WORD(nr);
455     oal_bitops old = *p;
456     *p = old & ~mask;
457 
458     (VOID)LOS_IntRestore(int_save);
459     return (old & mask) != 0;
460 #endif
461 }
462 
463 /* ****************************************************************************
464  功能描述  : 封装各个操作系统平台下对某个位进行原子清0操作。
465  输入参数  : nr: 需要清零的位
466              p_addr需要清零的变量地址
467  输出参数  : 无
468  返 回 值  :
469 **************************************************************************** */
oal_bit_atomic_clear(hi_s32 nr,HI_VOLATILE oal_bitops * p_addr)470 static inline hi_void oal_bit_atomic_clear(hi_s32 nr, HI_VOLATILE oal_bitops *p_addr)
471 {
472 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
473     clear_bit(nr, p_addr);
474 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
475     UINTPTR int_save;
476     int_save = LOS_IntLock();
477 
478     const oal_bitops mask = IS_BIT_SET(nr);
479     oal_bitops *p = ((oal_bitops *)p_addr) + BIT_WORD(nr);
480     *p &= ~mask;
481 
482     (VOID)LOS_IntRestore(int_save);
483 #endif
484 }
485 
486 
487 #ifdef __cplusplus
488 #if __cplusplus
489 }
490 #endif
491 #endif
492 
493 #endif /* end of oal_atomic.h */
494