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