summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2015-02-13 16:21:36 +0000
committerian <ian@FreeBSD.org>2015-02-13 16:21:36 +0000
commit68023855e86ca07fa26e05298b542ed56ce32878 (patch)
tree2ab14dc94b71ce94730612912567cf42bfcdd2f4 /sys/arm
parent180276472cc13f04474f4c6d2a748edf4819057a (diff)
downloadFreeBSD-src-68023855e86ca07fa26e05298b542ed56ce32878.zip
FreeBSD-src-68023855e86ca07fa26e05298b542ed56ce32878.tar.gz
MFC r266083, r267597:
Give suitably-endowed ARMs a register similar to the x86 TSC register.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/cpufunc.c53
-rw-r--r--sys/arm/include/cpu.h26
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
OpenPOWER on IntegriCloud