Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2010-2014 Intel Corporation 3 : : */ 4 : : 5 : : #ifndef _RTE_SPINLOCK_X86_64_H_ 6 : : #define _RTE_SPINLOCK_X86_64_H_ 7 : : 8 : : #include "generic/rte_spinlock.h" 9 : : #include "rte_rtm.h" 10 : : #include "rte_branch_prediction.h" 11 : : #include "rte_common.h" 12 : : #include "rte_pause.h" 13 : : #include "rte_cycles.h" 14 : : 15 : : #ifdef __cplusplus 16 : : extern "C" { 17 : : #endif 18 : : 19 : : #define RTE_RTM_MAX_RETRIES (20) 20 : : #define RTE_XABORT_LOCK_BUSY (0xff) 21 : : 22 : : #ifndef RTE_FORCE_INTRINSICS 23 : : static inline void 24 : : rte_spinlock_lock(rte_spinlock_t *sl) 25 : : __rte_no_thread_safety_analysis 26 : : { 27 : : int lock_val = 1; 28 : 9259931 : asm volatile ( 29 : : "1:\n" 30 : : "xchg %[locked], %[lv]\n" 31 : : "test %[lv], %[lv]\n" 32 : : "jz 3f\n" 33 : : "2:\n" 34 : : "pause\n" 35 : : "cmpl $0, %[locked]\n" 36 : : "jnz 2b\n" 37 : : "jmp 1b\n" 38 : : "3:\n" 39 : : : [locked] "=m" (sl->locked), [lv] "=q" (lock_val) 40 : : : "[lv]" (lock_val) 41 : : : "memory"); 42 : 480145 : } 43 : : 44 : : static inline void 45 : : rte_spinlock_unlock (rte_spinlock_t *sl) 46 : : __rte_no_thread_safety_analysis 47 : : { 48 : : int unlock_val = 0; 49 : 13468475 : asm volatile ( 50 : : "xchg %[locked], %[ulv]\n" 51 : : : [locked] "=m" (sl->locked), [ulv] "=q" (unlock_val) 52 : : : "[ulv]" (unlock_val) 53 : : : "memory"); 54 : 1900152 : } 55 : : 56 : : static inline int 57 : : rte_spinlock_trylock (rte_spinlock_t *sl) 58 : : __rte_no_thread_safety_analysis 59 : : { 60 : : int lockval = 1; 61 : : 62 : 4207530 : asm volatile ( 63 : : "xchg %[locked], %[lockval]" 64 : : : [locked] "=m" (sl->locked), [lockval] "=q" (lockval) 65 : : : "[lockval]" (lockval) 66 : : : "memory"); 67 : : 68 [ + - ]: 3832 : return lockval == 0; 69 : : } 70 : : #endif 71 : : 72 : : extern uint8_t rte_rtm_supported; 73 : : 74 : : static inline int rte_tm_supported(void) 75 : : { 76 [ # # # # ]: 0 : return rte_rtm_supported; 77 : : } 78 : : 79 : : static inline int 80 : 0 : rte_try_tm(volatile RTE_ATOMIC(int) *lock) 81 : : { 82 : : int i, retries; 83 : : 84 [ # # ]: 0 : if (!rte_rtm_supported) 85 : : return 0; 86 : : 87 : : retries = RTE_RTM_MAX_RETRIES; 88 : : 89 [ # # ]: 0 : while (likely(retries--)) { 90 : : 91 : : unsigned int status = rte_xbegin(); 92 : : 93 [ # # ]: 0 : if (likely(RTE_XBEGIN_STARTED == status)) { 94 [ # # ]: 0 : if (unlikely(*lock)) 95 : : rte_xabort(RTE_XABORT_LOCK_BUSY); 96 : : else 97 : : return 1; 98 : : } 99 [ # # ]: 0 : while (*lock) 100 : : rte_pause(); 101 : : 102 [ # # ]: 0 : if ((status & RTE_XABORT_CONFLICT) || 103 [ # # ]: 0 : ((status & RTE_XABORT_EXPLICIT) && 104 [ # # ]: 0 : (RTE_XABORT_CODE(status) == RTE_XABORT_LOCK_BUSY))) { 105 : : /* add a small delay before retrying, basing the 106 : : * delay on the number of times we've already tried, 107 : : * to give a back-off type of behaviour. We 108 : : * randomize trycount by taking bits from the tsc count 109 : : */ 110 : 0 : int try_count = RTE_RTM_MAX_RETRIES - retries; 111 : 0 : int pause_count = (rte_rdtsc() & 0x7) | 1; 112 : 0 : pause_count <<= try_count; 113 [ # # ]: 0 : for (i = 0; i < pause_count; i++) 114 : : rte_pause(); 115 : 0 : continue; 116 : : } 117 : : 118 [ # # ]: 0 : if ((status & RTE_XABORT_RETRY) == 0) /* do not retry */ 119 : : break; 120 : : } 121 : : return 0; 122 : : } 123 : : 124 : : static inline void 125 : : rte_spinlock_lock_tm(rte_spinlock_t *sl) 126 : : __rte_no_thread_safety_analysis 127 : : { 128 : : if (likely(rte_try_tm(&sl->locked))) 129 : : return; 130 : : 131 : : rte_spinlock_lock(sl); /* fall-back */ 132 : : } 133 : : 134 : : static inline int 135 : : rte_spinlock_trylock_tm(rte_spinlock_t *sl) 136 : : __rte_no_thread_safety_analysis 137 : : { 138 : : if (likely(rte_try_tm(&sl->locked))) 139 : : return 1; 140 : : 141 : : return rte_spinlock_trylock(sl); 142 : : } 143 : : 144 : : static inline void 145 : : rte_spinlock_unlock_tm(rte_spinlock_t *sl) 146 : : __rte_no_thread_safety_analysis 147 : : { 148 : : if (unlikely(sl->locked)) 149 : : rte_spinlock_unlock(sl); 150 : : else 151 : : rte_xend(); 152 : : } 153 : : 154 : : static inline void 155 : : rte_spinlock_recursive_lock_tm(rte_spinlock_recursive_t *slr) 156 : : __rte_no_thread_safety_analysis 157 : : { 158 : : if (likely(rte_try_tm(&slr->sl.locked))) 159 : : return; 160 : : 161 : : rte_spinlock_recursive_lock(slr); /* fall-back */ 162 : : } 163 : : 164 : : static inline void 165 : : rte_spinlock_recursive_unlock_tm(rte_spinlock_recursive_t *slr) 166 : : __rte_no_thread_safety_analysis 167 : : { 168 : : if (unlikely(slr->sl.locked)) 169 : : rte_spinlock_recursive_unlock(slr); 170 : : else 171 : : rte_xend(); 172 : : } 173 : : 174 : : static inline int 175 : : rte_spinlock_recursive_trylock_tm(rte_spinlock_recursive_t *slr) 176 : : __rte_no_thread_safety_analysis 177 : : { 178 : : if (likely(rte_try_tm(&slr->sl.locked))) 179 : : return 1; 180 : : 181 : : return rte_spinlock_recursive_trylock(slr); 182 : : } 183 : : 184 : : #ifdef __cplusplus 185 : : } 186 : : #endif 187 : : 188 : : #endif /* _RTE_SPINLOCK_X86_64_H_ */