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