1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Cavium, Inc
3  * Copyright(c) 2020 Arm Limited
4  */
5 
6 #ifndef _RTE_CYCLES_ARM64_H_
7 #define _RTE_CYCLES_ARM64_H_
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 #include "generic/rte_cycles.h"
14 
15 /** Read generic counter frequency */
16 static __rte_always_inline uint64_t
__rte_arm64_cntfrq(void)17 __rte_arm64_cntfrq(void)
18 {
19 	uint64_t freq;
20 
21 	asm volatile("mrs %0, cntfrq_el0" : "=r" (freq));
22 	return freq;
23 }
24 
25 /** Read generic counter */
26 static __rte_always_inline uint64_t
__rte_arm64_cntvct(void)27 __rte_arm64_cntvct(void)
28 {
29 	uint64_t tsc;
30 
31 	asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
32 	return tsc;
33 }
34 
35 static __rte_always_inline uint64_t
__rte_arm64_cntvct_precise(void)36 __rte_arm64_cntvct_precise(void)
37 {
38 	asm volatile("isb" : : : "memory");
39 	return __rte_arm64_cntvct();
40 }
41 
42 /**
43  * Read the time base register.
44  *
45  * @return
46  *   The time base for this lcore.
47  */
48 #ifndef RTE_ARM_EAL_RDTSC_USE_PMU
49 /**
50  * This call is portable to any ARMv8 architecture, however, typically
51  * cntvct_el0 runs at <= 100MHz and it may be imprecise for some tasks.
52  */
53 static __rte_always_inline uint64_t
rte_rdtsc(void)54 rte_rdtsc(void)
55 {
56 	return __rte_arm64_cntvct();
57 }
58 #else
59 /**
60  * This is an alternative method to enable rte_rdtsc() with high resolution
61  * PMU cycles counter.The cycle counter runs at cpu frequency and this scheme
62  * uses ARMv8 PMU subsystem to get the cycle counter at userspace, However,
63  * access to PMU cycle counter from user space is not enabled by default in
64  * arm64 linux kernel.
65  * It is possible to enable cycle counter at user space access by configuring
66  * the PMU from the privileged mode (kernel space).
67  *
68  * asm volatile("msr pmintenset_el1, %0" : : "r" ((u64)(0 << 31)));
69  * asm volatile("msr pmcntenset_el0, %0" :: "r" BIT(31));
70  * asm volatile("msr pmuserenr_el0, %0" : : "r"(BIT(0) | BIT(2)));
71  * asm volatile("mrs %0, pmcr_el0" : "=r" (val));
72  * val |= (BIT(0) | BIT(2));
73  * isb();
74  * asm volatile("msr pmcr_el0, %0" : : "r" (val));
75  *
76  */
77 
78 /** Read PMU cycle counter */
79 static __rte_always_inline uint64_t
__rte_arm64_pmccntr(void)80 __rte_arm64_pmccntr(void)
81 {
82 	uint64_t tsc;
83 
84 	asm volatile("mrs %0, pmccntr_el0" : "=r"(tsc));
85 	return tsc;
86 }
87 
88 static __rte_always_inline uint64_t
rte_rdtsc(void)89 rte_rdtsc(void)
90 {
91 	return __rte_arm64_pmccntr();
92 }
93 #endif
94 
95 static __rte_always_inline uint64_t
rte_rdtsc_precise(void)96 rte_rdtsc_precise(void)
97 {
98 	asm volatile("isb" : : : "memory");
99 	return rte_rdtsc();
100 }
101 
102 static __rte_always_inline uint64_t
rte_get_tsc_cycles(void)103 rte_get_tsc_cycles(void)
104 {
105 	return rte_rdtsc();
106 }
107 
108 #ifdef __cplusplus
109 }
110 #endif
111 
112 #endif /* _RTE_CYCLES_ARM64_H_ */
113