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