xref: /dpdk/lib/eal/arm/rte_power_intrinsics.c (revision 2f1a90f0455b4920df3a767ab5d9be37dcbf0d12)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2021 Intel Corporation
3  */
4 
5 #include <errno.h>
6 
7 #include "rte_cpuflags.h"
8 #include "rte_power_intrinsics.h"
9 
10 /**
11  *  Set wfet_en if WFET is supported
12  */
13 #ifdef RTE_ARCH_64
14 static uint8_t wfet_en;
15 #endif /* RTE_ARCH_64 */
16 
17 RTE_INIT(rte_power_intrinsics_init)
18 {
19 #ifdef RTE_ARCH_64
20 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WFXT))
21 		wfet_en = 1;
22 #endif /* RTE_ARCH_64 */
23 }
24 
25 /**
26  * This function uses WFE/WFET instruction to make lcore suspend
27  * execution on ARM.
28  */
29 int
30 rte_power_monitor(const struct rte_power_monitor_cond *pmc,
31 		const uint64_t tsc_timestamp)
32 {
33 #ifdef RTE_ARCH_64
34 	const unsigned int lcore_id = rte_lcore_id();
35 	uint64_t cur_value;
36 
37 	/* prevent non-EAL thread from using this API */
38 	if (lcore_id >= RTE_MAX_LCORE)
39 		return -EINVAL;
40 
41 	if (pmc == NULL)
42 		return -EINVAL;
43 
44 	if (pmc->fn == NULL)
45 		return -EINVAL;
46 
47 	switch (pmc->size) {
48 	case sizeof(uint8_t):
49 		__RTE_ARM_LOAD_EXC_8(pmc->addr, cur_value, rte_memory_order_relaxed);
50 		break;
51 	case sizeof(uint16_t):
52 		__RTE_ARM_LOAD_EXC_16(pmc->addr, cur_value, rte_memory_order_relaxed);
53 		break;
54 	case sizeof(uint32_t):
55 		__RTE_ARM_LOAD_EXC_32(pmc->addr, cur_value, rte_memory_order_relaxed);
56 		break;
57 	case sizeof(uint64_t):
58 		__RTE_ARM_LOAD_EXC_64(pmc->addr, cur_value, rte_memory_order_relaxed);
59 		break;
60 	default:
61 		return -EINVAL; /* unexpected size */
62 	}
63 
64 	if (wfet_en)
65 		__RTE_ARM_WFET(tsc_timestamp)
66 	else
67 		__RTE_ARM_WFE()
68 
69 	return 0;
70 #else
71 	RTE_SET_USED(pmc);
72 	RTE_SET_USED(tsc_timestamp);
73 
74 	return -ENOTSUP;
75 #endif /* RTE_ARCH_64 */
76 }
77 
78 /**
79  * This function is not supported on ARM.
80  */
81 int
82 rte_power_pause(const uint64_t tsc_timestamp)
83 {
84 	RTE_SET_USED(tsc_timestamp);
85 
86 	return -ENOTSUP;
87 }
88 
89 /**
90  * This function uses SEV instruction to wake up all cores
91  * on ARM.
92  * Note that lcore_id is not used here.
93  */
94 int
95 rte_power_monitor_wakeup(const unsigned int lcore_id)
96 {
97 	RTE_SET_USED(lcore_id);
98 
99 #ifdef RTE_ARCH_64
100 	__RTE_ARM_SEV()
101 	return 0;
102 #else
103 	return -ENOTSUP;
104 #endif /* RTE_ARCH_64 */
105 }
106 
107 int
108 rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[],
109 		const uint32_t num, const uint64_t tsc_timestamp)
110 {
111 	RTE_SET_USED(pmc);
112 	RTE_SET_USED(num);
113 	RTE_SET_USED(tsc_timestamp);
114 
115 	return -ENOTSUP;
116 }
117