eal: remove sync version of power monitor
[dpdk.git] / lib / librte_eal / x86 / rte_power_intrinsics.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4
5 #include "rte_power_intrinsics.h"
6
7 static bool wait_supported;
8
9 static inline uint64_t
10 __get_umwait_val(const volatile void *p, const uint8_t sz)
11 {
12         switch (sz) {
13         case sizeof(uint8_t):
14                 return *(const volatile uint8_t *)p;
15         case sizeof(uint16_t):
16                 return *(const volatile uint16_t *)p;
17         case sizeof(uint32_t):
18                 return *(const volatile uint32_t *)p;
19         case sizeof(uint64_t):
20                 return *(const volatile uint64_t *)p;
21         default:
22                 /* shouldn't happen */
23                 RTE_ASSERT(0);
24                 return 0;
25         }
26 }
27
28 static inline int
29 __check_val_size(const uint8_t sz)
30 {
31         switch (sz) {
32         case sizeof(uint8_t):  /* fall-through */
33         case sizeof(uint16_t): /* fall-through */
34         case sizeof(uint32_t): /* fall-through */
35         case sizeof(uint64_t): /* fall-through */
36                 return 0;
37         default:
38                 /* unexpected size */
39                 return -1;
40         }
41 }
42
43 /**
44  * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
45  * For more information about usage of these instructions, please refer to
46  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
47  */
48 int
49 rte_power_monitor(const struct rte_power_monitor_cond *pmc,
50                 const uint64_t tsc_timestamp)
51 {
52         const uint32_t tsc_l = (uint32_t)tsc_timestamp;
53         const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
54
55         /* prevent user from running this instruction if it's not supported */
56         if (!wait_supported)
57                 return -ENOTSUP;
58
59         if (pmc == NULL)
60                 return -EINVAL;
61
62         if (__check_val_size(pmc->data_sz) < 0)
63                 return -EINVAL;
64
65         /*
66          * we're using raw byte codes for now as only the newest compiler
67          * versions support this instruction natively.
68          */
69
70         /* set address for UMONITOR */
71         asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
72                         :
73                         : "D"(pmc->addr));
74
75         if (pmc->mask) {
76                 const uint64_t cur_value = __get_umwait_val(
77                                 pmc->addr, pmc->data_sz);
78                 const uint64_t masked = cur_value & pmc->mask;
79
80                 /* if the masked value is already matching, abort */
81                 if (masked == pmc->val)
82                         return 0;
83         }
84         /* execute UMWAIT */
85         asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
86                         : /* ignore rflags */
87                         : "D"(0), /* enter C0.2 */
88                           "a"(tsc_l), "d"(tsc_h));
89
90         return 0;
91 }
92
93 /**
94  * This function uses TPAUSE instruction  and will enter C0.2 state. For more
95  * information about usage of this instruction, please refer to Intel(R) 64 and
96  * IA-32 Architectures Software Developer's Manual.
97  */
98 int
99 rte_power_pause(const uint64_t tsc_timestamp)
100 {
101         const uint32_t tsc_l = (uint32_t)tsc_timestamp;
102         const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
103
104         /* prevent user from running this instruction if it's not supported */
105         if (!wait_supported)
106                 return -ENOTSUP;
107
108         /* execute TPAUSE */
109         asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;"
110                         : /* ignore rflags */
111                         : "D"(0), /* enter C0.2 */
112                         "a"(tsc_l), "d"(tsc_h));
113
114         return 0;
115 }
116
117 RTE_INIT(rte_power_intrinsics_init) {
118         struct rte_cpu_intrinsics i;
119
120         rte_cpu_get_intrinsics_support(&i);
121
122         if (i.power_monitor && i.power_pause)
123                 wait_supported = 1;
124 }