1 #ifndef __ARM_TIME_H__
2 #define __ARM_TIME_H__
3
4 #include <asm/sysregs.h>
5 #include <asm/system.h>
6 #include <asm/cpuerrata.h>
7
8 #define DT_MATCH_TIMER \
9 DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
10 DT_MATCH_COMPATIBLE("arm,armv8-timer")
11
12 typedef uint64_t cycles_t;
13
14 /*
15 * Ensure that reads of the counter are treated the same as memory reads
16 * for the purposes of ordering by subsequent memory barriers.
17 */
18 #if defined(CONFIG_ARM_64)
19 #define read_cntpct_enforce_ordering(val) do { \
20 uint64_t tmp, _val = (val); \
21 \
22 asm volatile( \
23 "eor %0, %1, %1\n" \
24 "add %0, sp, %0\n" \
25 "ldr xzr, [%0]" \
26 : "=r" (tmp) : "r" (_val)); \
27 } while (0)
28 #else
29 #define read_cntpct_enforce_ordering(val) do {} while (0)
30 #endif
31
read_cntpct_stable(void)32 static inline cycles_t read_cntpct_stable(void)
33 {
34 /*
35 * ARM_WORKAROUND_858921: Cortex-A73 (all versions) counter read
36 * can return a wrong value when the counter crosses a 32bit boundary.
37 */
38 if ( !check_workaround_858921() )
39 return READ_SYSREG64(CNTPCT_EL0);
40 else
41 {
42 /*
43 * A recommended workaround for erratum 858921 is to:
44 * 1- Read twice CNTPCT.
45 * 2- Compare bit[32] of the two read values.
46 * - If bit[32] is different, keep the old value.
47 * - If bit[32] is the same, keep the new value.
48 */
49 cycles_t old, new;
50 old = READ_SYSREG64(CNTPCT_EL0);
51 new = READ_SYSREG64(CNTPCT_EL0);
52 return (((old ^ new) >> 32) & 1) ? old : new;
53 }
54 }
55
get_cycles(void)56 static inline cycles_t get_cycles(void)
57 {
58 cycles_t cnt;
59
60 isb();
61 cnt = read_cntpct_stable();
62
63 /*
64 * If there is not any barrier here. When get_cycles being used in
65 * some seqlock critical context in the future, the seqlock can be
66 * speculated potentially.
67 *
68 * To prevent seqlock from being speculated silently, we add a barrier
69 * here defensively. Normally, we just need an ISB here is enough, but
70 * considering the minimum performance cost. We prefer to use enforce
71 * order here.
72 */
73 read_cntpct_enforce_ordering(cnt);
74
75 return cnt;
76 }
77
78 /* List of timer's IRQ */
79 enum timer_ppi
80 {
81 TIMER_PHYS_SECURE_PPI = 0,
82 TIMER_PHYS_NONSECURE_PPI = 1,
83 TIMER_VIRT_PPI = 2,
84 TIMER_HYP_PPI = 3,
85 TIMER_HYP_VIRT_PPI = 4,
86 MAX_TIMER_PPI = 5,
87 };
88
89 /*
90 * Value of "clock-frequency" in the DT timer node if present.
91 * 0 means the property doesn't exist.
92 */
93 extern uint32_t timer_dt_clock_frequency;
94
95 /* Get one of the timer IRQ number */
96 unsigned int timer_get_irq(enum timer_ppi ppi);
97
98 /* Set up the timer interrupt on this CPU */
99 extern void init_timer_interrupt(void);
100
101 /* Counter value at boot time */
102 extern uint64_t boot_count;
103
104 extern s_time_t ticks_to_ns(uint64_t ticks);
105 extern uint64_t ns_to_ticks(s_time_t ns);
106
107 void preinit_xen_time(void);
108
109 void force_update_vcpu_system_time(struct vcpu *v);
110
111 #endif /* __ARM_TIME_H__ */
112 /*
113 * Local variables:
114 * mode: C
115 * c-file-style: "BSD"
116 * c-basic-offset: 4
117 * indent-tabs-mode: nil
118 * End:
119 */
120