xref: /dpdk/lib/eal/include/generic/rte_power_intrinsics.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 
5 #ifndef _RTE_POWER_INTRINSIC_H_
6 #define _RTE_POWER_INTRINSIC_H_
7 
8 #include <inttypes.h>
9 
10 #include <rte_spinlock.h>
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /**
17  * @file
18  * Advanced power management operations.
19  *
20  * This file define APIs for advanced power management,
21  * which are architecture-dependent.
22  */
23 
24 /** Size of the opaque data in monitor condition */
25 #define RTE_POWER_MONITOR_OPAQUE_SZ 4
26 
27 /**
28  * Callback definition for monitoring conditions. Callbacks with this signature
29  * will be used by `rte_power_monitor()` to check if the entering of power
30  * optimized state should be aborted.
31  *
32  * @param val
33  *   The value read from memory.
34  * @param opaque
35  *   Callback-specific data.
36  *
37  * @return
38  *   0 if entering of power optimized state should proceed
39  *   -1 if entering of power optimized state should be aborted
40  */
41 typedef int (*rte_power_monitor_clb_t)(const uint64_t val,
42 		const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ]);
43 
44 struct rte_power_monitor_cond {
45 	volatile void *addr;  /**< Address to monitor for changes */
46 	uint8_t size;    /**< Data size (in bytes) that will be read from the
47 	                  *   monitored memory location (`addr`). Can be 1, 2,
48 	                  *   4, or 8. Supplying any other value will result in
49 	                  *   an error.
50 	                  */
51 	rte_power_monitor_clb_t fn; /**< Callback to be used to check if
52 	                             *   entering power optimized state should
53 	                             *   be aborted.
54 	                             */
55 	uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ];
56 	/**< Callback-specific data */
57 };
58 
59 /**
60  * Monitor specific address for changes. This will cause the CPU to enter an
61  * architecture-defined optimized power state until either the specified
62  * memory address is written to, a certain TSC timestamp is reached, or other
63  * reasons cause the CPU to wake up.
64  *
65  * Additionally, an expected value (`pmc->val`), mask (`pmc->mask`), and data
66  * size (`pmc->size`) are provided in the `pmc` power monitoring condition. If
67  * the mask is non-zero, the current value pointed to by the `pmc->addr` pointer
68  * will be read and compared against the expected value, and if they match, the
69  * entering of optimized power state will be aborted. This is intended to
70  * prevent the CPU from entering optimized power state and waiting on a write
71  * that has already happened by the time this API is called.
72  *
73  * @warning It is responsibility of the user to check if this function is
74  *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
75  *
76  * @param pmc
77  *   The monitoring condition structure.
78  * @param tsc_timestamp
79  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
80  *   architecture-dependent.
81  *
82  * @return
83  *   0 on success
84  *   -EINVAL on invalid parameters
85  *   -ENOTSUP if unsupported
86  */
87 int rte_power_monitor(const struct rte_power_monitor_cond *pmc,
88 		const uint64_t tsc_timestamp);
89 
90 /**
91  * Wake up a specific lcore that is in a power optimized state and is monitoring
92  * an address.
93  *
94  * @note It is safe to call this function if the lcore in question is not
95  *   sleeping. The function will have no effect.
96  *
97  * @note This function will *not* wake up a core that is in a power optimized
98  *   state due to calling `rte_power_pause`.
99  *
100  * @param lcore_id
101  *   Lcore ID of a sleeping thread.
102  */
103 int rte_power_monitor_wakeup(const unsigned int lcore_id);
104 
105 /**
106  * Enter an architecture-defined optimized power state until a certain TSC
107  * timestamp is reached.
108  *
109  * @warning It is responsibility of the user to check if this function is
110  *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
111  *
112  * @param tsc_timestamp
113  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
114  *   architecture-dependent.
115  *
116  * @return
117  *   0 on success
118  *   -EINVAL on invalid parameters
119  *   -ENOTSUP if unsupported
120  */
121 int rte_power_pause(const uint64_t tsc_timestamp);
122 
123 /**
124  * Monitor a set of addresses for changes. This will cause the CPU to enter an
125  * architecture-defined optimized power state until either one of the specified
126  * memory addresses is written to, a certain TSC timestamp is reached, or other
127  * reasons cause the CPU to wake up.
128  *
129  * Additionally, `expected` 64-bit values and 64-bit masks are provided. If
130  * mask is non-zero, the current value pointed to by the `p` pointer will be
131  * checked against the expected value, and if they do not match, the entering of
132  * optimized power state may be aborted.
133  *
134  * @warning It is responsibility of the user to check if this function is
135  *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
136  *   Failing to do so may result in an illegal CPU instruction error.
137  *
138  * @param pmc
139  *   An array of monitoring condition structures.
140  * @param num
141  *   Length of the `pmc` array.
142  * @param tsc_timestamp
143  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
144  *   architecture-dependent.
145  *
146  * @return
147  *   0 on success
148  *   -EINVAL on invalid parameters
149  *   -ENOTSUP if unsupported
150  */
151 int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[],
152 		const uint32_t num, const uint64_t tsc_timestamp);
153 
154 #ifdef __cplusplus
155 }
156 #endif
157 
158 #endif /* _RTE_POWER_INTRINSIC_H_ */
159