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