xref: /freebsd/sys/dev/qat/qat_api/common/utils/lac_lock_free_stack.h (revision 682f135f5de39cfc24cfd529ea8a161e94c76c8e)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2026 Intel Corporation */
3 #ifndef LAC_LOCK_FREE_STACK_H_1
4 #define LAC_LOCK_FREE_STACK_H_1
5 #include "lac_mem_pools.h"
6 
7 #ifdef __LP64__
8 typedef unsigned int atomic_int __attribute__((mode(TI)));
9 #else
10 typedef unsigned int atomic_int __attribute__((mode(DI)));
11 #endif
12 
13 typedef union {
14 	struct {
15 		unsigned long ctr;
16 		void *ptr;
17 	};
18 	atomic_int atomic;
19 } pointer_t;
20 
21 typedef struct {
22 	volatile pointer_t top;
23 } lock_free_stack_t;
24 
25 static inline char
lac_atomic_cmp_swap(volatile pointer_t * ptr,pointer_t old_val,pointer_t new_val)26 lac_atomic_cmp_swap(volatile pointer_t *ptr,
27 		    pointer_t old_val,
28 		    pointer_t new_val)
29 {
30 	uint64_t new_high, new_low, old_high, old_low;
31 	char res;
32 
33 	old_low = old_val.ctr;
34 	old_high = (uintptr_t)old_val.ptr;
35 	new_low = new_val.ctr;
36 	new_high = (uintptr_t)new_val.ptr;
37 
38 	__asm volatile("lock;cmpxchg16b\t%1"
39 		       : "=@cce"(res), "+m"(*ptr), "+a"(old_low), "+d"(old_high)
40 		       : "b"(new_low), "c"(new_high)
41 		       : "memory", "cc");
42 	return (res);
43 }
44 
45 static inline lac_mem_blk_t *
pop(lock_free_stack_t * stack)46 pop(lock_free_stack_t *stack)
47 {
48 	pointer_t old_top;
49 	pointer_t new_top;
50 	lac_mem_blk_t *next;
51 
52 	do {
53 		old_top.atomic = stack->top.atomic;
54 		next = old_top.ptr;
55 		if (NULL == next)
56 			return next;
57 
58 		new_top.ptr = next->pNext;
59 		new_top.ctr = old_top.ctr + 1;
60 	} while (!lac_atomic_cmp_swap(&stack->top, old_top, new_top));
61 
62 	return next;
63 }
64 
65 static inline void
push(lock_free_stack_t * stack,lac_mem_blk_t * val)66 push(lock_free_stack_t *stack, lac_mem_blk_t *val)
67 {
68 	pointer_t new_top;
69 	pointer_t old_top;
70 
71 	do {
72 		old_top.atomic = stack->top.atomic;
73 		val->pNext = old_top.ptr;
74 		new_top.ptr = val;
75 		new_top.ctr = old_top.ctr + 1;
76 	} while (!lac_atomic_cmp_swap(&stack->top, old_top, new_top));
77 }
78 
79 static inline lock_free_stack_t
_init_stack(void)80 _init_stack(void)
81 {
82 	lock_free_stack_t stack = { .top.atomic = 0 };
83 	return stack;
84 }
85 
86 static inline lac_mem_blk_t *
top(lock_free_stack_t * stack)87 top(lock_free_stack_t *stack)
88 {
89 	pointer_t old_top = stack->top;
90 	lac_mem_blk_t *next = old_top.ptr;
91 	return next;
92 }
93 
94 #endif
95