diff options
Diffstat (limited to 'arch/arm64/include/asm/arch_timer.h')
-rw-r--r-- | arch/arm64/include/asm/arch_timer.h | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index fbe0ca31a99c..eaa5bbe3fa87 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h | |||
@@ -20,13 +20,55 @@ | |||
20 | #define __ASM_ARCH_TIMER_H | 20 | #define __ASM_ARCH_TIMER_H |
21 | 21 | ||
22 | #include <asm/barrier.h> | 22 | #include <asm/barrier.h> |
23 | #include <asm/sysreg.h> | ||
23 | 24 | ||
24 | #include <linux/bug.h> | 25 | #include <linux/bug.h> |
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/jump_label.h> | ||
26 | #include <linux/types.h> | 28 | #include <linux/types.h> |
27 | 29 | ||
28 | #include <clocksource/arm_arch_timer.h> | 30 | #include <clocksource/arm_arch_timer.h> |
29 | 31 | ||
32 | #if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) | ||
33 | extern struct static_key_false arch_timer_read_ool_enabled; | ||
34 | #define needs_fsl_a008585_workaround() \ | ||
35 | static_branch_unlikely(&arch_timer_read_ool_enabled) | ||
36 | #else | ||
37 | #define needs_fsl_a008585_workaround() false | ||
38 | #endif | ||
39 | |||
40 | u32 __fsl_a008585_read_cntp_tval_el0(void); | ||
41 | u32 __fsl_a008585_read_cntv_tval_el0(void); | ||
42 | u64 __fsl_a008585_read_cntvct_el0(void); | ||
43 | |||
44 | /* | ||
45 | * The number of retries is an arbitrary value well beyond the highest number | ||
46 | * of iterations the loop has been observed to take. | ||
47 | */ | ||
48 | #define __fsl_a008585_read_reg(reg) ({ \ | ||
49 | u64 _old, _new; \ | ||
50 | int _retries = 200; \ | ||
51 | \ | ||
52 | do { \ | ||
53 | _old = read_sysreg(reg); \ | ||
54 | _new = read_sysreg(reg); \ | ||
55 | _retries--; \ | ||
56 | } while (unlikely(_old != _new) && _retries); \ | ||
57 | \ | ||
58 | WARN_ON_ONCE(!_retries); \ | ||
59 | _new; \ | ||
60 | }) | ||
61 | |||
62 | #define arch_timer_reg_read_stable(reg) \ | ||
63 | ({ \ | ||
64 | u64 _val; \ | ||
65 | if (needs_fsl_a008585_workaround()) \ | ||
66 | _val = __fsl_a008585_read_##reg(); \ | ||
67 | else \ | ||
68 | _val = read_sysreg(reg); \ | ||
69 | _val; \ | ||
70 | }) | ||
71 | |||
30 | /* | 72 | /* |
31 | * These register accessors are marked inline so the compiler can | 73 | * These register accessors are marked inline so the compiler can |
32 | * nicely work out which register we want, and chuck away the rest of | 74 | * nicely work out which register we want, and chuck away the rest of |
@@ -38,19 +80,19 @@ void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) | |||
38 | if (access == ARCH_TIMER_PHYS_ACCESS) { | 80 | if (access == ARCH_TIMER_PHYS_ACCESS) { |
39 | switch (reg) { | 81 | switch (reg) { |
40 | case ARCH_TIMER_REG_CTRL: | 82 | case ARCH_TIMER_REG_CTRL: |
41 | asm volatile("msr cntp_ctl_el0, %0" : : "r" (val)); | 83 | write_sysreg(val, cntp_ctl_el0); |
42 | break; | 84 | break; |
43 | case ARCH_TIMER_REG_TVAL: | 85 | case ARCH_TIMER_REG_TVAL: |
44 | asm volatile("msr cntp_tval_el0, %0" : : "r" (val)); | 86 | write_sysreg(val, cntp_tval_el0); |
45 | break; | 87 | break; |
46 | } | 88 | } |
47 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { | 89 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { |
48 | switch (reg) { | 90 | switch (reg) { |
49 | case ARCH_TIMER_REG_CTRL: | 91 | case ARCH_TIMER_REG_CTRL: |
50 | asm volatile("msr cntv_ctl_el0, %0" : : "r" (val)); | 92 | write_sysreg(val, cntv_ctl_el0); |
51 | break; | 93 | break; |
52 | case ARCH_TIMER_REG_TVAL: | 94 | case ARCH_TIMER_REG_TVAL: |
53 | asm volatile("msr cntv_tval_el0, %0" : : "r" (val)); | 95 | write_sysreg(val, cntv_tval_el0); |
54 | break; | 96 | break; |
55 | } | 97 | } |
56 | } | 98 | } |
@@ -61,48 +103,38 @@ void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) | |||
61 | static __always_inline | 103 | static __always_inline |
62 | u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) | 104 | u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) |
63 | { | 105 | { |
64 | u32 val; | ||
65 | |||
66 | if (access == ARCH_TIMER_PHYS_ACCESS) { | 106 | if (access == ARCH_TIMER_PHYS_ACCESS) { |
67 | switch (reg) { | 107 | switch (reg) { |
68 | case ARCH_TIMER_REG_CTRL: | 108 | case ARCH_TIMER_REG_CTRL: |
69 | asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val)); | 109 | return read_sysreg(cntp_ctl_el0); |
70 | break; | ||
71 | case ARCH_TIMER_REG_TVAL: | 110 | case ARCH_TIMER_REG_TVAL: |
72 | asm volatile("mrs %0, cntp_tval_el0" : "=r" (val)); | 111 | return arch_timer_reg_read_stable(cntp_tval_el0); |
73 | break; | ||
74 | } | 112 | } |
75 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { | 113 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { |
76 | switch (reg) { | 114 | switch (reg) { |
77 | case ARCH_TIMER_REG_CTRL: | 115 | case ARCH_TIMER_REG_CTRL: |
78 | asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val)); | 116 | return read_sysreg(cntv_ctl_el0); |
79 | break; | ||
80 | case ARCH_TIMER_REG_TVAL: | 117 | case ARCH_TIMER_REG_TVAL: |
81 | asm volatile("mrs %0, cntv_tval_el0" : "=r" (val)); | 118 | return arch_timer_reg_read_stable(cntv_tval_el0); |
82 | break; | ||
83 | } | 119 | } |
84 | } | 120 | } |
85 | 121 | ||
86 | return val; | 122 | BUG(); |
87 | } | 123 | } |
88 | 124 | ||
89 | static inline u32 arch_timer_get_cntfrq(void) | 125 | static inline u32 arch_timer_get_cntfrq(void) |
90 | { | 126 | { |
91 | u32 val; | 127 | return read_sysreg(cntfrq_el0); |
92 | asm volatile("mrs %0, cntfrq_el0" : "=r" (val)); | ||
93 | return val; | ||
94 | } | 128 | } |
95 | 129 | ||
96 | static inline u32 arch_timer_get_cntkctl(void) | 130 | static inline u32 arch_timer_get_cntkctl(void) |
97 | { | 131 | { |
98 | u32 cntkctl; | 132 | return read_sysreg(cntkctl_el1); |
99 | asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl)); | ||
100 | return cntkctl; | ||
101 | } | 133 | } |
102 | 134 | ||
103 | static inline void arch_timer_set_cntkctl(u32 cntkctl) | 135 | static inline void arch_timer_set_cntkctl(u32 cntkctl) |
104 | { | 136 | { |
105 | asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); | 137 | write_sysreg(cntkctl, cntkctl_el1); |
106 | } | 138 | } |
107 | 139 | ||
108 | static inline u64 arch_counter_get_cntpct(void) | 140 | static inline u64 arch_counter_get_cntpct(void) |
@@ -116,12 +148,8 @@ static inline u64 arch_counter_get_cntpct(void) | |||
116 | 148 | ||
117 | static inline u64 arch_counter_get_cntvct(void) | 149 | static inline u64 arch_counter_get_cntvct(void) |
118 | { | 150 | { |
119 | u64 cval; | ||
120 | |||
121 | isb(); | 151 | isb(); |
122 | asm volatile("mrs %0, cntvct_el0" : "=r" (cval)); | 152 | return arch_timer_reg_read_stable(cntvct_el0); |
123 | |||
124 | return cval; | ||
125 | } | 153 | } |
126 | 154 | ||
127 | static inline int arch_timer_arch_init(void) | 155 | static inline int arch_timer_arch_init(void) |