1 /* 2 * arch/arm64/include/asm/arch_timer.h 3 * 4 * Copyright (C) 2012 ARM Ltd. 5 * Author: Marc Zyngier <marc.zyngier@arm.com> 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 #ifndef __ASM_ARCH_TIMER_H 20 #define __ASM_ARCH_TIMER_H 21 22 #include <asm/barrier.h> 23 #include <asm/sysreg.h> 24 25 #include <linux/bug.h> 26 #include <linux/init.h> 27 #include <linux/jump_label.h> 28 #include <linux/smp.h> 29 #include <linux/types.h> 30 31 #include <clocksource/arm_arch_timer.h> 32 33 #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) 34 #define has_erratum_handler(h) \ 35 ({ \ 36 const struct arch_timer_erratum_workaround *__wa; \ 37 __wa = __this_cpu_read(timer_unstable_counter_workaround); \ 38 (__wa && __wa->h); \ 39 }) 40 41 #define erratum_handler(h) \ 42 ({ \ 43 const struct arch_timer_erratum_workaround *__wa; \ 44 __wa = __this_cpu_read(timer_unstable_counter_workaround); \ 45 (__wa && __wa->h) ? __wa->h : arch_timer_##h; \ 46 }) 47 48 #else 49 #define has_erratum_handler(h) false 50 #define erratum_handler(h) (arch_timer_##h) 51 #endif 52 53 enum arch_timer_erratum_match_type { 54 ate_match_dt, 55 ate_match_local_cap_id, 56 ate_match_acpi_oem_info, 57 }; 58 59 struct clock_event_device; 60 61 struct arch_timer_erratum_workaround { 62 enum arch_timer_erratum_match_type match_type; 63 const void *id; 64 const char *desc; 65 u32 (*read_cntp_tval_el0)(void); 66 u32 (*read_cntv_tval_el0)(void); 67 u64 (*read_cntpct_el0)(void); 68 u64 (*read_cntvct_el0)(void); 69 int (*set_next_event_phys)(unsigned long, struct clock_event_device *); 70 int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 71 }; 72 73 DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *, 74 timer_unstable_counter_workaround); 75 76 /* inline sysreg accessors that make erratum_handler() work */ 77 static inline notrace u32 arch_timer_read_cntp_tval_el0(void) 78 { 79 return read_sysreg(cntp_tval_el0); 80 } 81 82 static inline notrace u32 arch_timer_read_cntv_tval_el0(void) 83 { 84 return read_sysreg(cntv_tval_el0); 85 } 86 87 static inline notrace u64 arch_timer_read_cntpct_el0(void) 88 { 89 return read_sysreg(cntpct_el0); 90 } 91 92 static inline notrace u64 arch_timer_read_cntvct_el0(void) 93 { 94 return read_sysreg(cntvct_el0); 95 } 96 97 #define arch_timer_reg_read_stable(reg) \ 98 ({ \ 99 u64 _val; \ 100 \ 101 preempt_disable_notrace(); \ 102 _val = erratum_handler(read_ ## reg)(); \ 103 preempt_enable_notrace(); \ 104 \ 105 _val; \ 106 }) 107 108 /* 109 * These register accessors are marked inline so the compiler can 110 * nicely work out which register we want, and chuck away the rest of 111 * the code. 112 */ 113 static __always_inline 114 void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) 115 { 116 if (access == ARCH_TIMER_PHYS_ACCESS) { 117 switch (reg) { 118 case ARCH_TIMER_REG_CTRL: 119 write_sysreg(val, cntp_ctl_el0); 120 break; 121 case ARCH_TIMER_REG_TVAL: 122 write_sysreg(val, cntp_tval_el0); 123 break; 124 } 125 } else if (access == ARCH_TIMER_VIRT_ACCESS) { 126 switch (reg) { 127 case ARCH_TIMER_REG_CTRL: 128 write_sysreg(val, cntv_ctl_el0); 129 break; 130 case ARCH_TIMER_REG_TVAL: 131 write_sysreg(val, cntv_tval_el0); 132 break; 133 } 134 } 135 136 isb(); 137 } 138 139 static __always_inline 140 u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) 141 { 142 if (access == ARCH_TIMER_PHYS_ACCESS) { 143 switch (reg) { 144 case ARCH_TIMER_REG_CTRL: 145 return read_sysreg(cntp_ctl_el0); 146 case ARCH_TIMER_REG_TVAL: 147 return arch_timer_reg_read_stable(cntp_tval_el0); 148 } 149 } else if (access == ARCH_TIMER_VIRT_ACCESS) { 150 switch (reg) { 151 case ARCH_TIMER_REG_CTRL: 152 return read_sysreg(cntv_ctl_el0); 153 case ARCH_TIMER_REG_TVAL: 154 return arch_timer_reg_read_stable(cntv_tval_el0); 155 } 156 } 157 158 BUG(); 159 } 160 161 static inline u32 arch_timer_get_cntfrq(void) 162 { 163 return read_sysreg(cntfrq_el0); 164 } 165 166 static inline u32 arch_timer_get_cntkctl(void) 167 { 168 return read_sysreg(cntkctl_el1); 169 } 170 171 static inline void arch_timer_set_cntkctl(u32 cntkctl) 172 { 173 write_sysreg(cntkctl, cntkctl_el1); 174 isb(); 175 } 176 177 /* 178 * Ensure that reads of the counter are treated the same as memory reads 179 * for the purposes of ordering by subsequent memory barriers. 180 * 181 * This insanity brought to you by speculative system register reads, 182 * out-of-order memory accesses, sequence locks and Thomas Gleixner. 183 * 184 * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html 185 */ 186 #define arch_counter_enforce_ordering(val) do { \ 187 u64 tmp, _val = (val); \ 188 \ 189 asm volatile( \ 190 " eor %0, %1, %1\n" \ 191 " add %0, sp, %0\n" \ 192 " ldr xzr, [%0]" \ 193 : "=r" (tmp) : "r" (_val)); \ 194 } while (0) 195 196 static __always_inline u64 __arch_counter_get_cntpct_stable(void) 197 { 198 u64 cnt; 199 200 isb(); 201 cnt = arch_timer_reg_read_stable(cntpct_el0); 202 arch_counter_enforce_ordering(cnt); 203 return cnt; 204 } 205 206 static __always_inline u64 __arch_counter_get_cntpct(void) 207 { 208 u64 cnt; 209 210 isb(); 211 cnt = read_sysreg(cntpct_el0); 212 arch_counter_enforce_ordering(cnt); 213 return cnt; 214 } 215 216 static __always_inline u64 __arch_counter_get_cntvct_stable(void) 217 { 218 u64 cnt; 219 220 isb(); 221 cnt = arch_timer_reg_read_stable(cntvct_el0); 222 arch_counter_enforce_ordering(cnt); 223 return cnt; 224 } 225 226 static __always_inline u64 __arch_counter_get_cntvct(void) 227 { 228 u64 cnt; 229 230 isb(); 231 cnt = read_sysreg(cntvct_el0); 232 arch_counter_enforce_ordering(cnt); 233 return cnt; 234 } 235 236 #undef arch_counter_enforce_ordering 237 238 static inline int arch_timer_arch_init(void) 239 { 240 return 0; 241 } 242 243 #endif 244