]> git.lizzy.rs Git - plan9front.git/commitdiff
arm64: use generic timer virtual counter for cycles()
authorcinap_lenrek <cinap_lenrek@felloff.net>
Fri, 23 Jul 2021 15:10:01 +0000 (15:10 +0000)
committercinap_lenrek <cinap_lenrek@felloff.net>
Fri, 23 Jul 2021 15:10:01 +0000 (15:10 +0000)
We used to use performance cycle counter for cycles(),
but it is kind of useless in userspace as each core
has its own counter and hence not comparable between
cores. Also, the cycle counter stops counting when
the cores are idle.

Most callers expect cycles() to return a high resolution
timestamp instead, so do the best we can do here
and enable the userspace generic timer virtual counter.

sys/man/2/cputime
sys/src/9/bcm64/clock.c
sys/src/9/bcm64/sysreg.h
sys/src/libc/arm64/cycles.s

index 4d6440116341c26cd6ddc0d97635896e38bb3bb2..282e93aded3aa6ba27531d08f344470e6a0c0946 100644 (file)
@@ -39,6 +39,7 @@ if any, and stores it via
 Currently supported architectures are
 .BR 386 ,
 .BR amd64 ,
+.B arm64
 and
 .BR power ;
 on all others,
index f7b3e55f7fe07ce595471eb858a88762379e2d19..f5fcc47843c84387e25acadc47f5ae5eb49a14d7 100644 (file)
@@ -2,14 +2,14 @@
  * bcm283[56] timers
  *     System timers run at 1MHz (timers 1 and 2 are used by GPU)
  *     ARM timer usually runs at 250MHz (may be slower in low power modes)
- *     Cycle counter runs at 700MHz (unless overclocked)
  *    All are free-running up-counters
  *
  * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
  *   For smp on bcm2836, use local generic timer for interrupts on cpu1-3
  * Use ARM timer (32 bits) for perfticks
  * Use ARM timer to force immediate interrupt
- * Use cycle counter for cycles()
+ * Use performance cycle counter for lcycles()
+ * Use generic timer virtual counter for cycles()
  */
 
 #include "u.h"
@@ -118,6 +118,7 @@ clockinit(void)
        syswr(PMCR_EL0, 1<<6 | 7);
        syswr(PMCNTENSET, 1<<31);
        syswr(PMUSERENR_EL0, 1<<2);
+       syswr(CNTKCTL_EL1, 1<<1);
 
        syswr(CNTP_TVAL_EL0, ~0UL);
        if(m->machno == 0){
@@ -147,7 +148,19 @@ clockinit(void)
        t1 -= t0;
        m->cpuhz = 100 * t1;
        m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
-       m->cyclefreq = m->cpuhz;
+
+       /*
+        * Cyclefreq used to be the same as cpuhz as
+        * we where using the PMCCNTR_EL0 which counts
+        * per core cpu cycles. But is is kind of useless
+        * in userspace because each core has a differnet
+        * counter and it stops when the core is idle (WFI).
+        * So we change it to use the generic timer
+        * virtual counter register CNTVCT_EL0 instead
+        * running at the same frequency as system timer.
+        * (CNTFRQ_EL0 is WRONG on raspberry pi).
+        */
+       m->cyclefreq = SystimerFreq;
 
        if(m->machno == 0){
                tn->cs = 1<<3;
index c057bbba8a316b80fbb51758b78e0990e6d4c1e9..0d9b1b1724edc99106ba3be81a2c4793f3e1a480 100644 (file)
@@ -32,6 +32,8 @@
 #define PMUSERENR_EL0                  SYSREG(3,3,9,14,0)
 
 #define CNTPCT_EL0                     SYSREG(3,3,14,0,1)
+#define CNTVCT_EL0                     SYSREG(3,3,14,0,2)
+#define CNTKCTL_EL1                    SYSREG(3,0,14,1,0)
 #define CNTP_TVAL_EL0                  SYSREG(3,3,14,2,0)
 #define CNTP_CTL_EL0                   SYSREG(3,3,14,2,1)
 #define CNTP_CVAL_EL0                  SYSREG(3,3,14,2,2)
index 389ea201f3a7d0aa5ce29b70086a39c7f65bf7f0..03955b9ad48a6156aa7af675b810730b4160b211 100644 (file)
@@ -1,7 +1,7 @@
 #define        SYSREG(op0,op1,Cn,Cm,op2)       SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
-#define PMCCNTR_EL0                    SYSREG(3,3,9,13,0)
+#define CNTVCT_EL0                     SYSREG(3,3,14,0,2)
 
 TEXT cycles(SB), 1, $-4
-       MRS     PMCCNTR_EL0, R1
+       MRS     CNTVCT_EL0, R1
        MOV     R1, (R0)
        RETURN