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