xref: /dpdk/lib/eal/include/generic/rte_pause.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2017 Cavium, Inc
399a2dd95SBruce Richardson  * Copyright(c) 2019 Arm Limited
499a2dd95SBruce Richardson  */
599a2dd95SBruce Richardson 
699a2dd95SBruce Richardson #ifndef _RTE_PAUSE_H_
799a2dd95SBruce Richardson #define _RTE_PAUSE_H_
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson /**
1099a2dd95SBruce Richardson  * @file
1199a2dd95SBruce Richardson  *
1299a2dd95SBruce Richardson  * CPU pause operation.
1399a2dd95SBruce Richardson  */
1499a2dd95SBruce Richardson 
1599a2dd95SBruce Richardson #include <stdint.h>
1699a2dd95SBruce Richardson #include <assert.h>
171ec6a845STyler Retzlaff 
1899a2dd95SBruce Richardson #include <rte_common.h>
1999a2dd95SBruce Richardson #include <rte_atomic.h>
201ec6a845STyler Retzlaff #include <rte_stdatomic.h>
2199a2dd95SBruce Richardson 
22*719834a6SMattias Rönnblom #ifdef __cplusplus
23*719834a6SMattias Rönnblom extern "C" {
24*719834a6SMattias Rönnblom #endif
25*719834a6SMattias Rönnblom 
2699a2dd95SBruce Richardson /**
2799a2dd95SBruce Richardson  * Pause CPU execution for a short while
2899a2dd95SBruce Richardson  *
2999a2dd95SBruce Richardson  * This call is intended for tight loops which poll a shared resource or wait
3099a2dd95SBruce Richardson  * for an event. A short pause within the loop may reduce the power consumption.
3199a2dd95SBruce Richardson  */
3299a2dd95SBruce Richardson static inline void rte_pause(void);
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson /**
3599a2dd95SBruce Richardson  * Wait for *addr to be updated with a 16-bit expected value, with a relaxed
3699a2dd95SBruce Richardson  * memory ordering model meaning the loads around this API can be reordered.
3799a2dd95SBruce Richardson  *
3899a2dd95SBruce Richardson  * @param addr
3999a2dd95SBruce Richardson  *  A pointer to the memory location.
4099a2dd95SBruce Richardson  * @param expected
4199a2dd95SBruce Richardson  *  A 16-bit expected value to be in the memory location.
4299a2dd95SBruce Richardson  * @param memorder
4399a2dd95SBruce Richardson  *  Two different memory orders that can be specified:
441ec6a845STyler Retzlaff  *  rte_memory_order_acquire and rte_memory_order_relaxed.
4599a2dd95SBruce Richardson  */
4699a2dd95SBruce Richardson static __rte_always_inline void
4799a2dd95SBruce Richardson rte_wait_until_equal_16(volatile uint16_t *addr, uint16_t expected,
481ec6a845STyler Retzlaff 		rte_memory_order memorder);
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson /**
5199a2dd95SBruce Richardson  * Wait for *addr to be updated with a 32-bit expected value, with a relaxed
5299a2dd95SBruce Richardson  * memory ordering model meaning the loads around this API can be reordered.
5399a2dd95SBruce Richardson  *
5499a2dd95SBruce Richardson  * @param addr
5599a2dd95SBruce Richardson  *  A pointer to the memory location.
5699a2dd95SBruce Richardson  * @param expected
5799a2dd95SBruce Richardson  *  A 32-bit expected value to be in the memory location.
5899a2dd95SBruce Richardson  * @param memorder
5999a2dd95SBruce Richardson  *  Two different memory orders that can be specified:
601ec6a845STyler Retzlaff  *  rte_memory_order_acquire and rte_memory_order_relaxed.
6199a2dd95SBruce Richardson  */
6299a2dd95SBruce Richardson static __rte_always_inline void
6399a2dd95SBruce Richardson rte_wait_until_equal_32(volatile uint32_t *addr, uint32_t expected,
641ec6a845STyler Retzlaff 		rte_memory_order memorder);
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson /**
6799a2dd95SBruce Richardson  * Wait for *addr to be updated with a 64-bit expected value, with a relaxed
6899a2dd95SBruce Richardson  * memory ordering model meaning the loads around this API can be reordered.
6999a2dd95SBruce Richardson  *
7099a2dd95SBruce Richardson  * @param addr
7199a2dd95SBruce Richardson  *  A pointer to the memory location.
7299a2dd95SBruce Richardson  * @param expected
7399a2dd95SBruce Richardson  *  A 64-bit expected value to be in the memory location.
7499a2dd95SBruce Richardson  * @param memorder
7599a2dd95SBruce Richardson  *  Two different memory orders that can be specified:
761ec6a845STyler Retzlaff  *  rte_memory_order_acquire and rte_memory_order_relaxed.
7799a2dd95SBruce Richardson  */
7899a2dd95SBruce Richardson static __rte_always_inline void
7999a2dd95SBruce Richardson rte_wait_until_equal_64(volatile uint64_t *addr, uint64_t expected,
801ec6a845STyler Retzlaff 		rte_memory_order memorder);
8199a2dd95SBruce Richardson 
8299a2dd95SBruce Richardson #ifndef RTE_WAIT_UNTIL_EQUAL_ARCH_DEFINED
8399a2dd95SBruce Richardson static __rte_always_inline void
8499a2dd95SBruce Richardson rte_wait_until_equal_16(volatile uint16_t *addr, uint16_t expected,
851ec6a845STyler Retzlaff 		rte_memory_order memorder)
8699a2dd95SBruce Richardson {
871ec6a845STyler Retzlaff 	assert(memorder == rte_memory_order_acquire || memorder == rte_memory_order_relaxed);
8899a2dd95SBruce Richardson 
899290f8beSTyler Retzlaff 	while (rte_atomic_load_explicit((volatile __rte_atomic uint16_t *)addr, memorder)
909290f8beSTyler Retzlaff 			!= expected)
9199a2dd95SBruce Richardson 		rte_pause();
9299a2dd95SBruce Richardson }
9399a2dd95SBruce Richardson 
9499a2dd95SBruce Richardson static __rte_always_inline void
9599a2dd95SBruce Richardson rte_wait_until_equal_32(volatile uint32_t *addr, uint32_t expected,
961ec6a845STyler Retzlaff 		rte_memory_order memorder)
9799a2dd95SBruce Richardson {
981ec6a845STyler Retzlaff 	assert(memorder == rte_memory_order_acquire || memorder == rte_memory_order_relaxed);
9999a2dd95SBruce Richardson 
1009290f8beSTyler Retzlaff 	while (rte_atomic_load_explicit((volatile __rte_atomic uint32_t *)addr, memorder)
1019290f8beSTyler Retzlaff 			!= expected)
10299a2dd95SBruce Richardson 		rte_pause();
10399a2dd95SBruce Richardson }
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson static __rte_always_inline void
10699a2dd95SBruce Richardson rte_wait_until_equal_64(volatile uint64_t *addr, uint64_t expected,
1071ec6a845STyler Retzlaff 		rte_memory_order memorder)
10899a2dd95SBruce Richardson {
1091ec6a845STyler Retzlaff 	assert(memorder == rte_memory_order_acquire || memorder == rte_memory_order_relaxed);
11099a2dd95SBruce Richardson 
1119290f8beSTyler Retzlaff 	while (rte_atomic_load_explicit((volatile __rte_atomic uint64_t *)addr, memorder)
1129290f8beSTyler Retzlaff 			!= expected)
11399a2dd95SBruce Richardson 		rte_pause();
11499a2dd95SBruce Richardson }
115875f3509SFeifei Wang 
116875f3509SFeifei Wang /*
117875f3509SFeifei Wang  * Wait until *addr & mask makes the condition true. With a relaxed memory
118875f3509SFeifei Wang  * ordering model, the loads around this helper can be reordered.
119875f3509SFeifei Wang  *
120875f3509SFeifei Wang  * @param addr
121875f3509SFeifei Wang  *  A pointer to the memory location.
122875f3509SFeifei Wang  * @param mask
123875f3509SFeifei Wang  *  A mask of value bits in interest.
124875f3509SFeifei Wang  * @param cond
125875f3509SFeifei Wang  *  A symbol representing the condition.
126875f3509SFeifei Wang  * @param expected
127875f3509SFeifei Wang  *  An expected value to be in the memory location.
128875f3509SFeifei Wang  * @param memorder
129875f3509SFeifei Wang  *  Two different memory orders that can be specified:
1301ec6a845STyler Retzlaff  *  rte_memory_order_acquire and rte_memory_order_relaxed.
131875f3509SFeifei Wang  */
132875f3509SFeifei Wang #define RTE_WAIT_UNTIL_MASKED(addr, mask, cond, expected, memorder) do { \
133875f3509SFeifei Wang 	RTE_BUILD_BUG_ON(!__builtin_constant_p(memorder));               \
1341ec6a845STyler Retzlaff 	RTE_BUILD_BUG_ON((memorder) != rte_memory_order_acquire &&       \
1351ec6a845STyler Retzlaff 		(memorder) != rte_memory_order_relaxed);                 \
136875f3509SFeifei Wang 	typeof(*(addr)) expected_value = (expected);                     \
1371ec6a845STyler Retzlaff 	while (!((rte_atomic_load_explicit((addr), (memorder)) & (mask)) \
1381ec6a845STyler Retzlaff 			cond expected_value))                            \
139875f3509SFeifei Wang 		rte_pause();                                             \
140875f3509SFeifei Wang } while (0)
141875f3509SFeifei Wang #endif /* ! RTE_WAIT_UNTIL_EQUAL_ARCH_DEFINED */
14299a2dd95SBruce Richardson 
143*719834a6SMattias Rönnblom #ifdef __cplusplus
144*719834a6SMattias Rönnblom }
145*719834a6SMattias Rönnblom #endif
146*719834a6SMattias Rönnblom 
14799a2dd95SBruce Richardson #endif /* _RTE_PAUSE_H_ */
148