1 /* 2 * Timer tests for the ARM virt machine. 3 * 4 * Copyright (C) 2017, Alexander Graf <agraf@suse.de> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2. 7 */ 8 #include <libcflat.h> 9 #include <devicetree.h> 10 #include <errata.h> 11 #include <asm/timer.h> 12 #include <asm/delay.h> 13 #include <asm/processor.h> 14 #include <asm/gic.h> 15 #include <asm/io.h> 16 17 static bool ptimer_unsupported; 18 19 static void ptimer_unsupported_handler(struct pt_regs *regs, unsigned int esr) 20 { 21 ptimer_unsupported = true; 22 regs->pc += 4; 23 } 24 25 static u64 read_vtimer_counter(void) 26 { 27 isb(); 28 return read_sysreg(cntvct_el0); 29 } 30 31 static u64 read_vtimer_cval(void) 32 { 33 return read_sysreg(cntv_cval_el0); 34 } 35 36 static void write_vtimer_cval(u64 val) 37 { 38 write_sysreg(val, cntv_cval_el0); 39 isb(); 40 } 41 42 static s32 read_vtimer_tval(void) 43 { 44 return read_sysreg(cntv_tval_el0); 45 } 46 47 static void write_vtimer_tval(s32 val) 48 { 49 write_sysreg(val, cntv_tval_el0); 50 isb(); 51 } 52 53 static u64 read_vtimer_ctl(void) 54 { 55 return read_sysreg(cntv_ctl_el0); 56 } 57 58 static void write_vtimer_ctl(u64 val) 59 { 60 write_sysreg(val, cntv_ctl_el0); 61 isb(); 62 } 63 64 static u64 read_ptimer_counter(void) 65 { 66 isb(); 67 return read_sysreg(cntpct_el0); 68 } 69 70 static u64 read_ptimer_cval(void) 71 { 72 return read_sysreg(cntp_cval_el0); 73 } 74 75 static void write_ptimer_cval(u64 val) 76 { 77 write_sysreg(val, cntp_cval_el0); 78 isb(); 79 } 80 81 static s32 read_ptimer_tval(void) 82 { 83 return read_sysreg(cntp_tval_el0); 84 } 85 86 static void write_ptimer_tval(s32 val) 87 { 88 write_sysreg(val, cntp_tval_el0); 89 isb(); 90 } 91 92 static u64 read_ptimer_ctl(void) 93 { 94 return read_sysreg(cntp_ctl_el0); 95 } 96 97 static void write_ptimer_ctl(u64 val) 98 { 99 write_sysreg(val, cntp_ctl_el0); 100 isb(); 101 } 102 103 struct timer_info { 104 u32 irq; 105 volatile bool irq_received; 106 u64 (*read_counter)(void); 107 u64 (*read_cval)(void); 108 void (*write_cval)(u64); 109 s32 (*read_tval)(void); 110 void (*write_tval)(s32); 111 u64 (*read_ctl)(void); 112 void (*write_ctl)(u64); 113 }; 114 115 static struct timer_info vtimer_info = { 116 .irq_received = false, 117 .read_counter = read_vtimer_counter, 118 .read_cval = read_vtimer_cval, 119 .write_cval = write_vtimer_cval, 120 .read_tval = read_vtimer_tval, 121 .write_tval = write_vtimer_tval, 122 .read_ctl = read_vtimer_ctl, 123 .write_ctl = write_vtimer_ctl, 124 }; 125 126 static struct timer_info ptimer_info = { 127 .irq_received = false, 128 .read_counter = read_ptimer_counter, 129 .read_cval = read_ptimer_cval, 130 .write_cval = write_ptimer_cval, 131 .read_tval = read_ptimer_tval, 132 .write_tval = write_ptimer_tval, 133 .read_ctl = read_ptimer_ctl, 134 .write_ctl = write_ptimer_ctl, 135 }; 136 137 static void set_timer_irq_enabled(struct timer_info *info, bool enabled) 138 { 139 u32 irq = PPI(info->irq); 140 141 if (enabled) 142 gic_enable_irq(irq); 143 else 144 gic_disable_irq(irq); 145 } 146 147 static void irq_handler(struct pt_regs *regs) 148 { 149 struct timer_info *info; 150 u32 irqstat = gic_read_iar(); 151 u32 irqnr = gic_iar_irqnr(irqstat); 152 153 if (irqnr == PPI(vtimer_info.irq)) { 154 info = &vtimer_info; 155 } else if (irqnr == PPI(ptimer_info.irq)) { 156 info = &ptimer_info; 157 } else { 158 if (irqnr != GICC_INT_SPURIOUS) 159 gic_write_eoir(irqstat); 160 report_info("Unexpected interrupt: %d\n", irqnr); 161 return; 162 } 163 164 info->write_ctl(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE); 165 gic_write_eoir(irqstat); 166 167 info->irq_received = true; 168 } 169 170 /* Check that the timer condition is met. */ 171 static bool timer_pending(struct timer_info *info) 172 { 173 return (info->read_ctl() & ARCH_TIMER_CTL_ENABLE) && 174 (info->read_ctl() & ARCH_TIMER_CTL_ISTATUS); 175 } 176 177 static bool gic_timer_check_state(struct timer_info *info, 178 enum gic_irq_state expected_state) 179 { 180 int i; 181 182 /* Wait for up to 1s for the GIC to sample the interrupt. */ 183 for (i = 0; i < 10; i++) { 184 mdelay(100); 185 if (gic_irq_state(PPI(info->irq)) == expected_state) { 186 mdelay(100); 187 if (gic_irq_state(PPI(info->irq)) == expected_state) 188 return true; 189 } 190 } 191 192 return false; 193 } 194 195 static bool test_cval_10msec(struct timer_info *info) 196 { 197 u64 time_10ms = read_sysreg(cntfrq_el0) / 100; 198 u64 time_1us = time_10ms / 10000; 199 u64 before_timer, after_timer; 200 s64 difference; 201 202 /* Program timer to fire in 10 ms */ 203 before_timer = info->read_counter(); 204 info->write_cval(before_timer + time_10ms); 205 info->write_ctl(ARCH_TIMER_CTL_ENABLE); 206 207 /* Wait for the timer to fire */ 208 while (!timer_pending(info)) 209 ; 210 211 /* It fired, check how long it took */ 212 after_timer = info->read_counter(); 213 difference = after_timer - (before_timer + time_10ms); 214 215 report_info("After timer: 0x%016lx", after_timer); 216 report_info("Expected : 0x%016lx", before_timer + time_10ms); 217 report_info("Difference : %ld us", difference / time_1us); 218 219 if (difference < 0) { 220 printf("ISTATUS set too early\n"); 221 return false; 222 } 223 return difference < time_10ms; 224 } 225 226 static void disable_timer(struct timer_info *info) 227 { 228 info->write_ctl(0); 229 info->irq_received = false; 230 } 231 232 static void test_timer_pending(struct timer_info *info) 233 { 234 u64 now = info->read_counter(); 235 u64 time_10s = read_sysreg(cntfrq_el0) * 10; 236 u64 later = now + time_10s; 237 238 /* 239 * We don't want the irq handler to fire because that will change the 240 * timer state and we want to test the timer output signal. We can 241 * still read the pending state even if it's disabled. 242 */ 243 set_timer_irq_enabled(info, false); 244 245 /* Enable the timer, but schedule it for much later */ 246 info->write_cval(later); 247 info->write_ctl(ARCH_TIMER_CTL_ENABLE); 248 report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), 249 "not pending before"); 250 251 info->write_cval(now - 1); 252 report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_PENDING), 253 "interrupt signal pending"); 254 255 disable_timer(info); 256 set_timer_irq_enabled(info, true); 257 258 report(!info->irq_received, "no interrupt when timer is disabled"); 259 report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), 260 "interrupt signal no longer pending"); 261 262 info->write_cval(now - 1); 263 info->write_ctl(ARCH_TIMER_CTL_ENABLE | ARCH_TIMER_CTL_IMASK); 264 report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), 265 "interrupt signal not pending"); 266 267 disable_timer(info); 268 } 269 270 static void test_timer_cval(struct timer_info *info) 271 { 272 report(test_cval_10msec(info), "latency within 10 ms"); 273 report(info->irq_received, "interrupt received"); 274 275 disable_timer(info); 276 } 277 278 static void timer_do_wfi(struct timer_info *info) 279 { 280 local_irq_disable(); 281 if (info->irq_received) 282 goto out; 283 report_info("waiting for interrupt..."); 284 wfi(); 285 out: 286 local_irq_enable(); 287 } 288 289 static void test_timer_tval(struct timer_info *info) 290 { 291 u64 time_10ms = read_sysreg(cntfrq_el0) / 100; 292 s32 left; 293 int i; 294 295 info->write_tval(time_10ms); 296 info->write_ctl(ARCH_TIMER_CTL_ENABLE); 297 298 for (;;) { 299 timer_do_wfi(info); 300 left = info->read_tval(); 301 if (info->irq_received || left <= 0) 302 break; 303 } 304 305 /* Wait one second for the GIC to update the interrupt state. */ 306 if (left <= 0 && !info->irq_received) { 307 for (i = 0; i < 10; i++) { 308 timer_do_wfi(info); 309 if (info->irq_received) 310 break; 311 mdelay(100); 312 } 313 left = info->read_tval(); 314 } 315 316 report(info->irq_received, "interrupt received after TVAL/WFI"); 317 report(left <= 0, "timer has expired"); 318 report_info("TVAL is %d ticks", left); 319 320 disable_timer(info); 321 } 322 323 static void test_timer(struct timer_info *info) 324 { 325 test_timer_cval(info); 326 test_timer_pending(info); 327 test_timer_tval(info); 328 } 329 330 static void test_vtimer(void) 331 { 332 report_prefix_push("vtimer-busy-loop"); 333 test_timer(&vtimer_info); 334 report_prefix_pop(); 335 } 336 337 static void test_ptimer(void) 338 { 339 if (ptimer_unsupported) 340 return; 341 342 report_prefix_push("ptimer-busy-loop"); 343 test_timer(&ptimer_info); 344 report_prefix_pop(); 345 } 346 347 static void test_init(void) 348 { 349 assert(TIMER_PTIMER_IRQ != -1 && TIMER_VTIMER_IRQ != -1); 350 ptimer_info.irq = TIMER_PTIMER_IRQ; 351 vtimer_info.irq = TIMER_VTIMER_IRQ; 352 353 install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, ptimer_unsupported_handler); 354 ptimer_info.read_ctl(); 355 install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, NULL); 356 357 if (ptimer_unsupported && !ERRATA(7b6b46311a85)) { 358 report_skip("Skipping ptimer tests. Set ERRATA_7b6b46311a85=y to enable."); 359 } else if (ptimer_unsupported) { 360 report_fail("ptimer: read CNTP_CTL_EL0"); 361 report_info("ptimer: skipping remaining tests"); 362 } 363 364 gic_enable_defaults(); 365 366 install_irq_handler(EL1H_IRQ, irq_handler); 367 set_timer_irq_enabled(&ptimer_info, true); 368 set_timer_irq_enabled(&vtimer_info, true); 369 local_irq_enable(); 370 } 371 372 static void print_timer_info(void) 373 { 374 printf("CNTFRQ_EL0 : 0x%016lx\n", read_sysreg(cntfrq_el0)); 375 376 if (!ptimer_unsupported) { 377 printf("CNTPCT_EL0 : 0x%016lx\n", ptimer_info.read_counter()); 378 printf("CNTP_CTL_EL0 : 0x%016lx\n", ptimer_info.read_ctl()); 379 printf("CNTP_CVAL_EL0: 0x%016lx\n", ptimer_info.read_cval()); 380 } 381 382 printf("CNTVCT_EL0 : 0x%016lx\n", vtimer_info.read_counter()); 383 printf("CNTV_CTL_EL0 : 0x%016lx\n", vtimer_info.read_ctl()); 384 printf("CNTV_CVAL_EL0: 0x%016lx\n", vtimer_info.read_cval()); 385 } 386 387 int main(int argc, char **argv) 388 { 389 int i; 390 391 test_init(); 392 393 print_timer_info(); 394 395 if (argc == 1) { 396 test_vtimer(); 397 test_ptimer(); 398 } 399 400 for (i = 1; i < argc; ++i) { 401 if (strcmp(argv[i], "vtimer") == 0) 402 test_vtimer(); 403 if (strcmp(argv[i], "ptimer") == 0) 404 test_ptimer(); 405 } 406 407 return report_summary(); 408 } 409