diff options
-rw-r--r-- | sys/arm/arm/cpufunc.c | 53 | ||||
-rw-r--r-- | sys/arm/include/cpu.h | 26 |
2 files changed, 78 insertions, 1 deletions
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index 1f4bb2e..5013574 100644 --- a/sys/arm/arm/cpufunc.c +++ b/sys/arm/arm/cpufunc.c @@ -1397,6 +1397,53 @@ arm10_setup(args) } #endif /* CPU_ARM9E || CPU_ARM10 */ +#if defined(CPU_ARM1136) || defined(CPU_ARM1176) \ + || defined(CPU_MV_PJ4B) \ + || defined(CPU_CORTEXA) || defined(CPU_KRAIT) +static __inline void +cpu_scc_setup_ccnt(void) +{ +/* This is how you give userland access to the CCNT and PMCn + * registers. + * BEWARE! This gives write access also, which may not be what + * you want! + */ +#ifdef _PMC_USER_READ_WRITE_ +#if defined(CPU_ARM1136) || defined(CPU_ARM1176) + /* Use the Secure User and Non-secure Access Validation Control Register + * to allow userland access + */ + __asm volatile ("mcr p15, 0, %0, c15, c9, 0\n\t" + : + : "r"(0x00000001)); +#else + /* Set PMUSERENR[0] to allow userland access */ + __asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" + : + : "r"(0x00000001)); +#endif +#endif +#if defined(CPU_ARM1136) || defined(CPU_ARM1176) + /* Set PMCR[2,0] to enable counters and reset CCNT */ + __asm volatile ("mcr p15, 0, %0, c15, c12, 0\n\t" + : + : "r"(0x00000005)); +#else + /* Set up the PMCCNTR register as a cyclecounter: + * Set PMINTENCLR to 0xFFFFFFFF to block interrupts + * Set PMCR[2,0] to enable counters and reset CCNT + * Set PMCNTENSET to 0x80000000 to enable CCNT */ + __asm volatile ("mcr p15, 0, %0, c9, c14, 2\n\t" + "mcr p15, 0, %1, c9, c12, 0\n\t" + "mcr p15, 0, %2, c9, c12, 1\n\t" + : + : "r"(0xFFFFFFFF), + "r"(0x00000005), + "r"(0x80000000)); +#endif +} +#endif + #if defined(CPU_ARM1136) || defined(CPU_ARM1176) struct cpu_option arm11_options[] = { { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) }, @@ -1500,6 +1547,8 @@ arm11x6_setup(char *args) /* And again. */ cpu_idcache_wbinv_all(); + + cpu_scc_setup_ccnt(); } #endif /* CPU_ARM1136 || CPU_ARM1176 */ @@ -1534,6 +1583,8 @@ pj4bv7_setup(args) /* And again. */ cpu_idcache_wbinv_all(); + + cpu_scc_setup_ccnt(); } #endif /* CPU_MV_PJ4B */ @@ -1581,6 +1632,8 @@ cortexa_setup(char *args) #ifdef SMP armv7_auxctrl((1 << 6) | (1 << 0), (1 << 6) | (1 << 0)); /* Enable SMP + TLB broadcasting */ #endif + + cpu_scc_setup_ccnt(); } #endif /* CPU_CORTEXA */ diff --git a/sys/arm/include/cpu.h b/sys/arm/include/cpu.h index c6f7088..dd7b6ac 100644 --- a/sys/arm/include/cpu.h +++ b/sys/arm/include/cpu.h @@ -14,11 +14,35 @@ void swi_vm(void *); static __inline uint64_t get_cyclecount(void) { +/* This '#if' asks the question 'Does CP15/SCC include performance counters?' */ +#if defined(CPU_ARM1136) || defined(CPU_ARM1176) \ + || defined(CPU_MV_PJ4B) \ + || defined(CPU_CORTEXA) || defined(CPU_KRAIT) + uint32_t ccnt; + uint64_t ccnt64; + + /* + * Read PMCCNTR. Curses! Its only 32 bits. + * TODO: Fix this by catching overflow with interrupt? + */ +/* The ARMv6 vs ARMv7 divide is going to need a better way of + * distinguishing between them. + */ +#if defined(CPU_ARM1136) || defined(CPU_ARM1176) + /* ARMv6 - Earlier model SCCs */ + __asm __volatile("mrc p15, 0, %0, c15, c12, 1": "=r" (ccnt)); +#else + /* ARMv7 - Later model SCCs */ + __asm __volatile("mrc p15, 0, %0, c9, c13, 0": "=r" (ccnt)); +#endif + ccnt64 = (uint64_t)ccnt; + return (ccnt64); +#else /* No performance counters, so use binuptime(9). This is slooooow */ struct bintime bt; binuptime(&bt); return ((uint64_t)bt.sec << 56 | bt.frac >> 8); - +#endif } #endif |