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