eal: uninline power intrinsics
[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 inline uint64_t
8 __get_umwait_val(const volatile void *p, const uint8_t sz)
9 {
10         switch (sz) {
11         case sizeof(uint8_t):
12                 return *(const volatile uint8_t *)p;
13         case sizeof(uint16_t):
14                 return *(const volatile uint16_t *)p;
15         case sizeof(uint32_t):
16                 return *(const volatile uint32_t *)p;
17         case sizeof(uint64_t):
18                 return *(const volatile uint64_t *)p;
19         default:
20                 /* this is an intrinsic, so we can't have any error handling */
21                 RTE_ASSERT(0);
22                 return 0;
23         }
24 }
25
26 /**
27  * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
28  * For more information about usage of these instructions, please refer to
29  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
30  */
31 void
32 rte_power_monitor(const volatile void *p, const uint64_t expected_value,
33                 const uint64_t value_mask, const uint64_t tsc_timestamp,
34                 const uint8_t data_sz)
35 {
36         const uint32_t tsc_l = (uint32_t)tsc_timestamp;
37         const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
38         /*
39          * we're using raw byte codes for now as only the newest compiler
40          * versions support this instruction natively.
41          */
42
43         /* set address for UMONITOR */
44         asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
45                         :
46                         : "D"(p));
47
48         if (value_mask) {
49                 const uint64_t cur_value = __get_umwait_val(p, data_sz);
50                 const uint64_t masked = cur_value & value_mask;
51
52                 /* if the masked value is already matching, abort */
53                 if (masked == expected_value)
54                         return;
55         }
56         /* execute UMWAIT */
57         asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
58                         : /* ignore rflags */
59                         : "D"(0), /* enter C0.2 */
60                           "a"(tsc_l), "d"(tsc_h));
61 }
62
63 /**
64  * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
65  * For more information about usage of these instructions, please refer to
66  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
67  */
68 void
69 rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
70                 const uint64_t value_mask, const uint64_t tsc_timestamp,
71                 const uint8_t data_sz, rte_spinlock_t *lck)
72 {
73         const uint32_t tsc_l = (uint32_t)tsc_timestamp;
74         const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
75         /*
76          * we're using raw byte codes for now as only the newest compiler
77          * versions support this instruction natively.
78          */
79
80         /* set address for UMONITOR */
81         asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
82                         :
83                         : "D"(p));
84
85         if (value_mask) {
86                 const uint64_t cur_value = __get_umwait_val(p, data_sz);
87                 const uint64_t masked = cur_value & value_mask;
88
89                 /* if the masked value is already matching, abort */
90                 if (masked == expected_value)
91                         return;
92         }
93         rte_spinlock_unlock(lck);
94
95         /* execute UMWAIT */
96         asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
97                         : /* ignore rflags */
98                         : "D"(0), /* enter C0.2 */
99                           "a"(tsc_l), "d"(tsc_h));
100
101         rte_spinlock_lock(lck);
102 }
103
104 /**
105  * This function uses TPAUSE instruction  and will enter C0.2 state. For more
106  * information about usage of this instruction, please refer to Intel(R) 64 and
107  * IA-32 Architectures Software Developer's Manual.
108  */
109 void
110 rte_power_pause(const uint64_t tsc_timestamp)
111 {
112         const uint32_t tsc_l = (uint32_t)tsc_timestamp;
113         const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
114
115         /* execute TPAUSE */
116         asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;"
117                         : /* ignore rflags */
118                         : "D"(0), /* enter C0.2 */
119                         "a"(tsc_l), "d"(tsc_h));
120 }