Author: markm
Date: Wed May 14 19:11:15 2014
New Revision: 266083
URL: http://svnweb.freebsd.org/changeset/base/266083

Log:
  Give suitably-endowed ARMs a register similar to the x86 TSC register.
  
  Here, "suitably endowed" means that the System Control Coprocessor
  (#15) has Performance Monitoring Registers, including a CCNT (Cycle
  Count) register.
  
  The CCNT register is used in a way similar to the TSC register in
  x86 processors by the get_cyclecount(9) function. The entropy-harvesting
  thread is a heavy user of this function, and will benefit from not
  having to call binuptime(9) instead.
  
  One problem with the CCNT register is that it is 32-bit only, so
  the upper 32-bits of the returned number are always 0. The entropy
  harvester does not care, but in case any one else does, follow-up
  work may include an interrup trap to increment an upper-32-bit
  counter on CCNT overflow.
  
  Another problem is that the CCNT register is not readable in user-mode
  code; in can be made readable by userland, but then it is also
  writable, and so is a good chunk of the PMU system. For that reason,
  the CCNT is not enabled for user-mode access in this commit.
  
  Like the x86, there is one CCNT per core, so they don't all run in
  perfect sync.
  
  Reviewed by:  ian@ (an earlier version)
  Tested by:    ian@ (same earlier version)
  Committed from:       WANDBOARD-QUAD

Modified:
  head/sys/arm/arm/cpufunc.c
  head/sys/arm/include/cpu.h

Modified: head/sys/arm/arm/cpufunc.c
==============================================================================
--- head/sys/arm/arm/cpufunc.c  Wed May 14 19:02:00 2014        (r266082)
+++ head/sys/arm/arm/cpufunc.c  Wed May 14 19:11:15 2014        (r266083)
@@ -1398,6 +1398,37 @@ 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_
+       /* Set PMUSERENR[0] to allow userland access */
+       __asm volatile ("mcr    p15, 0, %0, c9, c14, 0\n\t"
+                       :
+                       : "r"(0x00000001));
+#endif
+        /* 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
+
 #if defined(CPU_ARM1136) || defined(CPU_ARM1176)
 struct cpu_option arm11_options[] = {
        { "cpu.cache",          BIC, OR,  (CPU_CONTROL_IC_ENABLE | 
CPU_CONTROL_DC_ENABLE) },
@@ -1501,6 +1532,8 @@ arm11x6_setup(char *args)
 
        /* And again. */
        cpu_idcache_wbinv_all();
+
+       cpu_scc_setup_ccnt();
 }
 #endif  /* CPU_ARM1136 || CPU_ARM1176 */
 
@@ -1535,6 +1568,8 @@ pj4bv7_setup(args)
 
        /* And again. */
        cpu_idcache_wbinv_all();
+
+       cpu_scc_setup_ccnt();
 }
 #endif /* CPU_MV_PJ4B */
 
@@ -1582,6 +1617,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 */
 

Modified: head/sys/arm/include/cpu.h
==============================================================================
--- head/sys/arm/include/cpu.h  Wed May 14 19:02:00 2014        (r266082)
+++ head/sys/arm/include/cpu.h  Wed May 14 19:11:15 2014        (r266083)
@@ -14,11 +14,26 @@ 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?
+        */
+       __asm __volatile("mrc p15, 0, %0, c9, c13, 0": "=r" (ccnt));
+       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
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to