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