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