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