xref: /dpdk/lib/eal/riscv/include/rte_cycles.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Cavium, Inc
3  * Copyright(c) 2022 StarFive
4  * Copyright(c) 2022 SiFive
5  * Copyright(c) 2022 Semihalf
6  */
7 
8 #ifndef RTE_CYCLES_RISCV_H
9 #define RTE_CYCLES_RISCV_H
10 
11 #include "generic/rte_cycles.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 #ifndef RTE_RISCV_RDTSC_USE_HPM
18 #define RTE_RISCV_RDTSC_USE_HPM 0
19 #endif
20 
21 /** Read wall time counter */
22 static __rte_always_inline uint64_t
23 __rte_riscv_rdtime(void)
24 {
25 	uint64_t tsc;
26 	asm volatile("csrr %0, time" : "=r" (tsc) : : "memory");
27 	return tsc;
28 }
29 
30 /** Read wall time counter ensuring no re-ordering */
31 static __rte_always_inline uint64_t
32 __rte_riscv_rdtime_precise(void)
33 {
34 	asm volatile("fence" : : : "memory");
35 	return __rte_riscv_rdtime();
36 }
37 
38 /** Read hart cycle counter */
39 static __rte_always_inline uint64_t
40 __rte_riscv_rdcycle(void)
41 {
42 	uint64_t tsc;
43 	asm volatile("csrr %0, cycle" : "=r" (tsc) : : "memory");
44 	return tsc;
45 }
46 
47 /** Read hart cycle counter ensuring no re-ordering */
48 static __rte_always_inline uint64_t
49 __rte_riscv_rdcycle_precise(void)
50 {
51 	asm volatile("fence" : : : "memory");
52 	return __rte_riscv_rdcycle();
53 }
54 
55 /**
56  * Read the time base register.
57  *
58  * @return
59  *   The time base for this lcore.
60  */
61 static __rte_always_inline uint64_t
62 rte_rdtsc(void)
63 {
64 	/**
65 	 * By default TIME userspace counter is used. It is stable and shared
66 	 * across cores. Although it's frequency may not be enough for all
67 	 * applications.
68 	 */
69 	if (!RTE_RISCV_RDTSC_USE_HPM)
70 		return __rte_riscv_rdtime();
71 	/**
72 	 * Alternatively HPM's CYCLE counter may be used. However this counter
73 	 * is not guaranteed by ISA to either be stable frequency or always
74 	 * enabled for userspace access (it may trap to kernel or firmware,
75 	 * though as of Linux kernel 5.13 it doesn't).
76 	 * It is also highly probable that values of this counter are not
77 	 * synchronized across cores. Therefore if it is to be used as a timer,
78 	 * it can only be used in the scope of a single core.
79 	 */
80 	return __rte_riscv_rdcycle();
81 }
82 
83 static inline uint64_t
84 rte_rdtsc_precise(void)
85 {
86 	if (!RTE_RISCV_RDTSC_USE_HPM)
87 		return __rte_riscv_rdtime_precise();
88 	return __rte_riscv_rdcycle_precise();
89 }
90 
91 static __rte_always_inline uint64_t
92 rte_get_tsc_cycles(void)
93 {
94 	return rte_rdtsc();
95 }
96 
97 #ifdef __cplusplus
98 }
99 #endif
100 
101 #endif /* RTE_CYCLES_RISCV_H */
102