Index: head/sys/arm/arm/pmu.c =================================================================== --- head/sys/arm/arm/pmu.c +++ head/sys/arm/arm/pmu.c @@ -94,16 +94,44 @@ { -1, 0 } }; +/* CCNT */ +#if __ARM_ARCH > 6 +int pmu_attched = 0; +uint32_t ccnt_hi[MAXCPU]; +#endif + +#define PMU_OVSR_C 0x80000000 /* Cycle Counter */ +#define PMU_IESR_C 0x80000000 /* Cycle Counter */ + static int pmu_intr(void *arg) { +#ifdef HWPMC_HOOKS struct trapframe *tf; - - tf = arg; +#endif + uint32_t r; +#if defined(__arm__) && (__ARM_ARCH > 6) + u_int cpu; + + cpu = PCPU_GET(cpuid); + + r = cp15_pmovsr_get(); + if (r & PMU_OVSR_C) { + atomic_add_32(&ccnt_hi[cpu], 1); + /* Clear the event. */ + r &= ~PMU_OVSR_C; + cp15_pmovsr_set(PMU_OVSR_C); + } +#else + r = 1; +#endif #ifdef HWPMC_HOOKS - if (pmc_intr) + /* Only call into the HWPMC framework if we know there is work. */ + if (r != 0 && pmc_intr) { + tf = arg; (*pmc_intr)(PCPU_GET(cpuid), tf); + } #endif return (FILTER_HANDLED); @@ -128,6 +156,9 @@ pmu_attach(device_t dev) { struct pmu_softc *sc; +#if defined(__arm__) && (__ARM_ARCH > 6) + uint32_t iesr; +#endif int err; int i; @@ -152,6 +183,20 @@ } } +#if defined(__arm__) && (__ARM_ARCH > 6) + /* Initialize to 0. */ + for (i = 0; i < MAXCPU; i++) + ccnt_hi[i] = 0; + + /* Enable the interrupt to fire on overflow. */ + iesr = cp15_pminten_get(); + iesr |= PMU_IESR_C; + cp15_pminten_set(iesr); + + /* Need this for getcyclecount() fast path. */ + pmu_attched |= 1; +#endif + return (0); } Index: head/sys/arm/conf/BEAGLEBONE =================================================================== --- head/sys/arm/conf/BEAGLEBONE +++ head/sys/arm/conf/BEAGLEBONE @@ -102,6 +102,9 @@ # Mailbox support device ti_mbox +# PMU support (for CCNT). +device pmu + # USB support device usb options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. Index: head/sys/arm/include/cpu.h =================================================================== --- head/sys/arm/include/cpu.h +++ head/sys/arm/include/cpu.h @@ -14,12 +14,42 @@ #ifdef _KERNEL #if __ARM_ARCH >= 6 #include -#endif +#ifdef DEV_PMU +#include +#define PMU_OVSR_C 0x80000000 /* Cycle Counter */ +extern uint32_t ccnt_hi[MAXCPU]; +extern int pmu_attched; +#endif /* DEV_PMU */ +#endif /* __ARM_ARCH >= 6 */ + static __inline uint64_t get_cyclecount(void) { #if __ARM_ARCH >= 6 - return cp15_pmccntr_get(); +#if (__ARM_ARCH > 6) && defined(DEV_PMU) + if (pmu_attched) { + u_int cpu; + uint64_t h, h2; + uint32_t l, r; + + cpu = PCPU_GET(cpuid); + h = (uint64_t)atomic_load_acq_32(&ccnt_hi[cpu]); + l = cp15_pmccntr_get(); + /* In case interrupts are disabled we need to check for overflow. */ + r = cp15_pmovsr_get(); + if (r & PMU_OVSR_C) { + atomic_add_32(&ccnt_hi[cpu], 1); + /* Clear the event. */ + cp15_pmovsr_set(PMU_OVSR_C); + } + /* Make sure there was no wrap-around while we read the lo half. */ + h2 = (uint64_t)atomic_load_acq_32(&ccnt_hi[cpu]); + if (h != h2) + l = cp15_pmccntr_get(); + return (h2 << 32 | l); + } else +#endif + return cp15_pmccntr_get(); #else /* No performance counters, so use binuptime(9). This is slooooow */ struct bintime bt; Index: head/sys/conf/options.arm =================================================================== --- head/sys/conf/options.arm +++ head/sys/conf/options.arm @@ -23,6 +23,7 @@ CPU_XSCALE_IXP435 opt_global.h CPU_XSCALE_PXA2X0 opt_global.h DEV_GIC opt_global.h +DEV_PMU opt_global.h EFI opt_platform.h FLASHADDR opt_global.h GIC_DEFAULT_ICFGR_INIT opt_global.h