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