arm64: use generic timer virtual counter for cycles()
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.
This commit is contained in:
parent
2c1727e55c
commit
c38fcb5dc3
4 changed files with 21 additions and 5 deletions
|
@ -39,6 +39,7 @@ if any, and stores it via
|
||||||
Currently supported architectures are
|
Currently supported architectures are
|
||||||
.BR 386 ,
|
.BR 386 ,
|
||||||
.BR amd64 ,
|
.BR amd64 ,
|
||||||
|
.B arm64
|
||||||
and
|
and
|
||||||
.BR power ;
|
.BR power ;
|
||||||
on all others,
|
on all others,
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
* bcm283[56] timers
|
* bcm283[56] timers
|
||||||
* System timers run at 1MHz (timers 1 and 2 are used by GPU)
|
* 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)
|
* 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
|
* All are free-running up-counters
|
||||||
*
|
*
|
||||||
* Use system timer 3 (64 bits) for hzclock interrupts and fastticks
|
* Use system timer 3 (64 bits) for hzclock interrupts and fastticks
|
||||||
* For smp on bcm2836, use local generic timer for interrupts on cpu1-3
|
* For smp on bcm2836, use local generic timer for interrupts on cpu1-3
|
||||||
* Use ARM timer (32 bits) for perfticks
|
* Use ARM timer (32 bits) for perfticks
|
||||||
* Use ARM timer to force immediate interrupt
|
* 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"
|
#include "u.h"
|
||||||
|
@ -118,6 +118,7 @@ clockinit(void)
|
||||||
syswr(PMCR_EL0, 1<<6 | 7);
|
syswr(PMCR_EL0, 1<<6 | 7);
|
||||||
syswr(PMCNTENSET, 1<<31);
|
syswr(PMCNTENSET, 1<<31);
|
||||||
syswr(PMUSERENR_EL0, 1<<2);
|
syswr(PMUSERENR_EL0, 1<<2);
|
||||||
|
syswr(CNTKCTL_EL1, 1<<1);
|
||||||
|
|
||||||
syswr(CNTP_TVAL_EL0, ~0UL);
|
syswr(CNTP_TVAL_EL0, ~0UL);
|
||||||
if(m->machno == 0){
|
if(m->machno == 0){
|
||||||
|
@ -147,7 +148,19 @@ clockinit(void)
|
||||||
t1 -= t0;
|
t1 -= t0;
|
||||||
m->cpuhz = 100 * t1;
|
m->cpuhz = 100 * t1;
|
||||||
m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
|
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){
|
if(m->machno == 0){
|
||||||
tn->cs = 1<<3;
|
tn->cs = 1<<3;
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#define PMUSERENR_EL0 SYSREG(3,3,9,14,0)
|
#define PMUSERENR_EL0 SYSREG(3,3,9,14,0)
|
||||||
|
|
||||||
#define CNTPCT_EL0 SYSREG(3,3,14,0,1)
|
#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_TVAL_EL0 SYSREG(3,3,14,2,0)
|
||||||
#define CNTP_CTL_EL0 SYSREG(3,3,14,2,1)
|
#define CNTP_CTL_EL0 SYSREG(3,3,14,2,1)
|
||||||
#define CNTP_CVAL_EL0 SYSREG(3,3,14,2,2)
|
#define CNTP_CVAL_EL0 SYSREG(3,3,14,2,2)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
|
#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
|
TEXT cycles(SB), 1, $-4
|
||||||
MRS PMCCNTR_EL0, R1
|
MRS CNTVCT_EL0, R1
|
||||||
MOV R1, (R0)
|
MOV R1, (R0)
|
||||||
RETURN
|
RETURN
|
||||||
|
|
Loading…
Reference in a new issue