agtimer.c revision 1.18
1/* $OpenBSD: agtimer.c,v 1.18 2021/03/11 11:16:56 jsg Exp $ */ 2/* 3 * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/queue.h> 22#include <sys/malloc.h> 23#include <sys/device.h> 24#include <sys/kernel.h> 25#include <sys/timetc.h> 26#include <sys/evcount.h> 27 28#include <machine/intr.h> 29#include <machine/bus.h> 30#include <machine/fdt.h> 31 32#include <dev/ofw/fdt.h> 33#include <dev/ofw/openfirm.h> 34 35/* registers */ 36#define GTIMER_CNTV_CTL_ENABLE (1 << 0) 37#define GTIMER_CNTV_CTL_IMASK (1 << 1) 38#define GTIMER_CNTV_CTL_ISTATUS (1 << 2) 39 40#define TIMER_FREQUENCY 24 * 1000 * 1000 /* ARM core clock */ 41int32_t agtimer_frequency = TIMER_FREQUENCY; 42 43u_int agtimer_get_timecount(struct timecounter *); 44 45static struct timecounter agtimer_timecounter = { 46 .tc_get_timecount = agtimer_get_timecount, 47 .tc_poll_pps = NULL, 48 .tc_counter_mask = 0xffffffff, 49 .tc_frequency = 0, 50 .tc_name = "agtimer", 51 .tc_quality = 0, 52 .tc_priv = NULL, 53 .tc_user = TC_AGTIMER, 54}; 55 56struct agtimer_pcpu_softc { 57 uint64_t pc_nexttickevent; 58 uint64_t pc_nextstatevent; 59 u_int32_t pc_ticks_err_sum; 60}; 61 62struct agtimer_softc { 63 struct device sc_dev; 64 int sc_node; 65 66 struct agtimer_pcpu_softc sc_pstat[MAXCPUS]; 67 68 u_int32_t sc_ticks_err_cnt; 69 u_int32_t sc_ticks_per_second; 70 u_int32_t sc_ticks_per_intr; 71 u_int32_t sc_statvar; 72 u_int32_t sc_statmin; 73 74#ifdef AMPTIMER_DEBUG 75 struct evcount sc_clk_count; 76 struct evcount sc_stat_count; 77#endif 78 void *sc_ih; 79}; 80 81int agtimer_match(struct device *, void *, void *); 82void agtimer_attach(struct device *, struct device *, void *); 83uint64_t agtimer_readcnt64(void); 84int agtimer_intr(void *); 85void agtimer_cpu_initclocks(void); 86void agtimer_delay(u_int); 87void agtimer_setstatclockrate(int stathz); 88void agtimer_set_clockrate(int32_t new_frequency); 89void agtimer_startclock(void); 90 91struct cfattach agtimer_ca = { 92 sizeof (struct agtimer_softc), agtimer_match, agtimer_attach 93}; 94 95struct cfdriver agtimer_cd = { 96 NULL, "agtimer", DV_DULL 97}; 98 99uint64_t 100agtimer_readcnt64(void) 101{ 102 uint64_t val0, val1; 103 104 /* 105 * Work around Cortex-A73 errata 858921, where there is a 106 * one-cycle window where the read might return the old value 107 * for the low 32 bits and the new value for the high 32 bits 108 * upon roll-over of the low 32 bits. 109 */ 110 __asm volatile("isb" ::: "memory"); 111 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val0)); 112 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val1)); 113 return ((val0 ^ val1) & 0x100000000ULL) ? val0 : val1; 114} 115 116static inline uint64_t 117agtimer_get_freq(void) 118{ 119 uint64_t val; 120 121 __asm volatile("mrs %x0, CNTFRQ_EL0" : "=r" (val)); 122 123 return (val); 124} 125 126static inline int 127agtimer_get_ctrl(void) 128{ 129 uint32_t val; 130 131 __asm volatile("mrs %x0, CNTV_CTL_EL0" : "=r" (val)); 132 133 return (val); 134} 135 136static inline int 137agtimer_set_ctrl(uint32_t val) 138{ 139 __asm volatile("msr CNTV_CTL_EL0, %x0" :: "r" (val)); 140 __asm volatile("isb" ::: "memory"); 141 142 return (0); 143} 144 145static inline int 146agtimer_set_tval(uint32_t val) 147{ 148 __asm volatile("msr CNTV_TVAL_EL0, %x0" :: "r" (val)); 149 __asm volatile("isb" ::: "memory"); 150 151 return (0); 152} 153 154int 155agtimer_match(struct device *parent, void *cfdata, void *aux) 156{ 157 struct fdt_attach_args *faa = (struct fdt_attach_args *)aux; 158 159 return (OF_is_compatible(faa->fa_node, "arm,armv7-timer") || 160 OF_is_compatible(faa->fa_node, "arm,armv8-timer")); 161} 162 163void 164agtimer_attach(struct device *parent, struct device *self, void *aux) 165{ 166 struct agtimer_softc *sc = (struct agtimer_softc *)self; 167 struct fdt_attach_args *faa = aux; 168 169 sc->sc_node = faa->fa_node; 170 171 if (agtimer_get_freq() != 0) 172 agtimer_frequency = agtimer_get_freq(); 173 agtimer_frequency = 174 OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency); 175 sc->sc_ticks_per_second = agtimer_frequency; 176 177 printf(": %d kHz\n", sc->sc_ticks_per_second / 1000); 178 179#ifdef AMPTIMER_DEBUG 180 evcount_attach(&sc->sc_clk_count, "clock", NULL); 181 evcount_attach(&sc->sc_stat_count, "stat", NULL); 182#endif 183 184 /* 185 * private timer and interrupts not enabled until 186 * timer configures 187 */ 188 189 arm_clock_register(agtimer_cpu_initclocks, agtimer_delay, 190 agtimer_setstatclockrate, agtimer_startclock); 191 192 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 193 agtimer_timecounter.tc_priv = sc; 194 195 tc_init(&agtimer_timecounter); 196} 197 198u_int 199agtimer_get_timecount(struct timecounter *tc) 200{ 201 uint64_t val; 202 203 /* 204 * No need to work around Cortex-A73 errata 858921 since we 205 * only look at the low 32 bits here. 206 */ 207 __asm volatile("isb" ::: "memory"); 208 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val)); 209 return (val & 0xffffffff); 210} 211 212int 213agtimer_intr(void *frame) 214{ 215 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 216 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 217 uint64_t now; 218 uint64_t nextevent; 219 uint32_t r; 220#if defined(USE_GTIMER_CMP) 221 int skip = 1; 222#else 223 int64_t delay; 224#endif 225 int rc = 0; 226 227 /* 228 * DSR - I know that the tick timer is 64 bits, but the following 229 * code deals with rollover, so there is no point in dealing 230 * with the 64 bit math, just let the 32 bit rollover 231 * do the right thing 232 */ 233 234 now = agtimer_readcnt64(); 235 236 while (pc->pc_nexttickevent <= now) { 237 pc->pc_nexttickevent += sc->sc_ticks_per_intr; 238 pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt; 239 240 /* looping a few times is faster than divide */ 241 while (pc->pc_ticks_err_sum > hz) { 242 pc->pc_nexttickevent += 1; 243 pc->pc_ticks_err_sum -= hz; 244 } 245 246#ifdef AMPTIMER_DEBUG 247 sc->sc_clk_count.ec_count++; 248#endif 249 rc = 1; 250 hardclock(frame); 251 } 252 while (pc->pc_nextstatevent <= now) { 253 do { 254 r = random() & (sc->sc_statvar -1); 255 } while (r == 0); /* random == 0 not allowed */ 256 pc->pc_nextstatevent += sc->sc_statmin + r; 257 258 /* XXX - correct nextstatevent? */ 259#ifdef AMPTIMER_DEBUG 260 sc->sc_stat_count.ec_count++; 261#endif 262 rc = 1; 263 statclock(frame); 264 } 265 266 if (pc->pc_nexttickevent < pc->pc_nextstatevent) 267 nextevent = pc->pc_nexttickevent; 268 else 269 nextevent = pc->pc_nextstatevent; 270 271 delay = nextevent - now; 272 if (delay < 0) 273 delay = 1; 274 275 agtimer_set_tval(delay); 276 277 return (rc); 278} 279 280void 281agtimer_set_clockrate(int32_t new_frequency) 282{ 283 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 284 285 agtimer_frequency = new_frequency; 286 287 if (sc == NULL) 288 return; 289 290 sc->sc_ticks_per_second = agtimer_frequency; 291 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 292 printf("agtimer0: adjusting clock: new tick rate %d kHz\n", 293 sc->sc_ticks_per_second / 1000); 294} 295 296void 297agtimer_cpu_initclocks(void) 298{ 299 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 300 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 301 uint32_t reg; 302 uint64_t next; 303 uint64_t kctl; 304 305 stathz = hz; 306 profhz = hz * 10; 307 308 if (sc->sc_ticks_per_second != agtimer_frequency) { 309 agtimer_set_clockrate(agtimer_frequency); 310 } 311 312 agtimer_setstatclockrate(stathz); 313 314 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 315 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 316 pc->pc_ticks_err_sum = 0; 317 318 /* configure virtual timer interrupt */ 319 sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2, 320 IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick"); 321 322 next = agtimer_readcnt64() + sc->sc_ticks_per_intr; 323 pc->pc_nexttickevent = pc->pc_nextstatevent = next; 324 325 reg = agtimer_get_ctrl(); 326 reg &= ~GTIMER_CNTV_CTL_IMASK; 327 reg |= GTIMER_CNTV_CTL_ENABLE; 328 agtimer_set_tval(sc->sc_ticks_per_second); 329 agtimer_set_ctrl(reg); 330 331 /* enable userland access to virtual counter */ 332 kctl = READ_SPECIALREG(CNTKCTL_EL1); 333 WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN); 334} 335 336void 337agtimer_delay(u_int usecs) 338{ 339 uint64_t clock, oclock, delta, delaycnt; 340 uint64_t csec, usec; 341 volatile int j; 342 343 if (usecs > (0x80000000 / agtimer_frequency)) { 344 csec = usecs / 10000; 345 usec = usecs % 10000; 346 347 delaycnt = (agtimer_frequency / 100) * csec + 348 (agtimer_frequency / 100) * usec / 10000; 349 } else { 350 delaycnt = agtimer_frequency * usecs / 1000000; 351 } 352 if (delaycnt <= 1) 353 for (j = 100; j > 0; j--) 354 ; 355 356 oclock = agtimer_readcnt64(); 357 while (1) { 358 for (j = 100; j > 0; j--) 359 ; 360 clock = agtimer_readcnt64(); 361 delta = clock - oclock; 362 if (delta > delaycnt) 363 break; 364 } 365} 366 367void 368agtimer_setstatclockrate(int newhz) 369{ 370 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 371 int minint, statint; 372 int s; 373 374 s = splclock(); 375 376 statint = sc->sc_ticks_per_second / newhz; 377 /* calculate largest 2^n which is smaller that just over half statint */ 378 sc->sc_statvar = 0x40000000; /* really big power of two */ 379 minint = statint / 2 + 100; 380 while (sc->sc_statvar > minint) 381 sc->sc_statvar >>= 1; 382 383 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 384 385 splx(s); 386 387 /* 388 * XXX this allows the next stat timer to occur then it switches 389 * to the new frequency. Rather than switching instantly. 390 */ 391} 392 393void 394agtimer_startclock(void) 395{ 396 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 397 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 398 uint64_t nextevent; 399 uint64_t kctl; 400 uint32_t reg; 401 402 nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr; 403 pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; 404 405 arm_intr_route(sc->sc_ih, 1, curcpu()); 406 407 reg = agtimer_get_ctrl(); 408 reg &= ~GTIMER_CNTV_CTL_IMASK; 409 reg |= GTIMER_CNTV_CTL_ENABLE; 410 agtimer_set_tval(sc->sc_ticks_per_second); 411 agtimer_set_ctrl(reg); 412 413 /* enable userland access to virtual counter */ 414 kctl = READ_SPECIALREG(CNTKCTL_EL1); 415 WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN); 416} 417 418void 419agtimer_init(void) 420{ 421 uint64_t cntfrq = 0; 422 423 /* XXX: Check for Generic Timer support. */ 424 cntfrq = agtimer_get_freq(); 425 426 if (cntfrq != 0) { 427 agtimer_frequency = cntfrq; 428 arm_clock_register(NULL, agtimer_delay, NULL, NULL); 429 } 430} 431