Index: head/sys/arm/arm/pmu.c =================================================================== --- head/sys/arm/arm/pmu.c (revision 290613) +++ head/sys/arm/arm/pmu.c (revision 290614) @@ -1,172 +1,217 @@ /*- * Copyright (c) 2015 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Performance Monitoring Unit */ #include __FBSDID("$FreeBSD$"); #include "opt_hwpmc_hooks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_RLEN 8 struct pmu_softc { struct resource *res[MAX_RLEN]; device_t dev; void *ih[MAX_RLEN]; }; static struct ofw_compat_data compat_data[] = { {"arm,armv8-pmuv3", 1}, {"arm,cortex-a17-pmu", 1}, {"arm,cortex-a15-pmu", 1}, {"arm,cortex-a12-pmu", 1}, {"arm,cortex-a9-pmu", 1}, {"arm,cortex-a8-pmu", 1}, {"arm,cortex-a7-pmu", 1}, {"arm,cortex-a5-pmu", 1}, {"arm,arm11mpcore-pmu", 1}, {"arm,arm1176-pmu", 1}, {"arm,arm1136-pmu", 1}, {"qcom,krait-pmu", 1}, {NULL, 0} }; static struct resource_spec pmu_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 6, RF_ACTIVE | RF_OPTIONAL }, { SYS_RES_IRQ, 7, RF_ACTIVE | RF_OPTIONAL }, { -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; +#endif + uint32_t r; +#if defined(__arm__) && (__ARM_ARCH > 6) + u_int cpu; - tf = arg; + 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); } static int pmu_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { device_set_desc(dev, "Performance Monitoring Unit"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int pmu_attach(device_t dev) { struct pmu_softc *sc; +#if defined(__arm__) && (__ARM_ARCH > 6) + uint32_t iesr; +#endif int err; int i; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, pmu_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Setup interrupt handler */ for (i = 0; i < MAX_RLEN; i++) { if (sc->res[i] == NULL) break; err = bus_setup_intr(dev, sc->res[i], INTR_MPSAFE | INTR_TYPE_MISC, pmu_intr, NULL, NULL, &sc->ih[i]); if (err) { device_printf(dev, "Unable to setup interrupt handler.\n"); return (ENXIO); } } + +#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); } static device_method_t pmu_methods[] = { DEVMETHOD(device_probe, pmu_probe), DEVMETHOD(device_attach, pmu_attach), { 0, 0 } }; static driver_t pmu_driver = { "pmu", pmu_methods, sizeof(struct pmu_softc), }; static devclass_t pmu_devclass; DRIVER_MODULE(pmu, simplebus, pmu_driver, pmu_devclass, 0, 0); Index: head/sys/arm/conf/BEAGLEBONE =================================================================== --- head/sys/arm/conf/BEAGLEBONE (revision 290613) +++ head/sys/arm/conf/BEAGLEBONE (revision 290614) @@ -1,144 +1,147 @@ # # BEAGLEBONE -- Custom configuration for the BeagleBone ARM development # platforms, check out http://www.beagleboard.org/bone and # http://www.beagleboard.org/black. This kernel config file is used for the # original BeagleBone and the BeagleBone Black. # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident BEAGLEBONE include "std.armv6" include "../ti/am335x/std.am335x" makeoptions MODULES_EXTRA="dtb/am335x am335x_dmtpps" options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS server support #options NFSD # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=cpsw0 # Boot device is 2nd slice on MMC/SD card options ROOTDEVNAME=\"ufs:mmcsd0s2\" # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards device sdhci # mmc/sd host controller # I2C support device iicbus device iic device ti_i2c device am335x_pmic # AM335x Power Management IC (TPC65217) device am335x_rtc # RTC support (power management only) #define am335x_dmtpps # Pulse Per Second capture driver # Console and misc device uart device uart_ns8250 device pty device snp device md device random # Entropy device # GPIO device gpio device gpioled device gpiobacklight # ADC support device ti_adc # Watchdog support # If we don't enable the watchdog driver, the system could potentially # reboot automatically because the boot loader might have enabled the # watchdog. device ti_wdt # TI Programmable Realtime Unit support device ti_pruss # 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. options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE device musb device umass device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) # Ethernet device loop device ether device mii device smscphy device cpsw device bpf # USB Ethernet support, requires miibus device miibus device axe # ASIX Electronics USB Ethernet # Device mode support and USFS template device usb_template # Control of the gadget device usfs # Pinmux device fdt_pinctrl # Flattened Device Tree options FDT # Configure using FDT/DTB data # Comment following lines for boot console on serial port device vt device videomode device hdmi device ums device ukbd device kbdmux Index: head/sys/arm/include/cpu.h =================================================================== --- head/sys/arm/include/cpu.h (revision 290613) +++ head/sys/arm/include/cpu.h (revision 290614) @@ -1,68 +1,98 @@ /* $NetBSD: cpu.h,v 1.2 2001/02/23 21:23:52 reinoud Exp $ */ /* $FreeBSD$ */ #ifndef MACHINE_CPU_H #define MACHINE_CPU_H #include #include #include void cpu_halt(void); void swi_vm(void *); #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; binuptime(&bt); return ((uint64_t)bt.sec << 56 | bt.frac >> 8); #endif } #endif #define TRAPF_USERMODE(frame) ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) #define TRAPF_PC(tfp) ((tfp)->tf_pc) #define cpu_getstack(td) ((td)->td_frame->tf_usr_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_usr_sp = (sp)) #define cpu_spinwait() /* nothing */ #define ARM_NVEC 8 #define ARM_VEC_ALL 0xffffffff extern vm_offset_t vector_page; /* * Params passed into initarm. If you change the size of this you will * need to update locore.S to allocate more memory on the stack before * it calls initarm. */ struct arm_boot_params { register_t abp_size; /* Size of this structure */ register_t abp_r0; /* r0 from the boot loader */ register_t abp_r1; /* r1 from the boot loader */ register_t abp_r2; /* r2 from the boot loader */ register_t abp_r3; /* r3 from the boot loader */ vm_offset_t abp_physaddr; /* The kernel physical address */ vm_offset_t abp_pagetable; /* The early page table */ }; void arm_vector_init(vm_offset_t, int); void fork_trampoline(void); void identify_arm_cpu(void); void *initarm(struct arm_boot_params *); extern char btext[]; extern char etext[]; int badaddr_read(void *, size_t, void *); #endif /* !MACHINE_CPU_H */ Index: head/sys/conf/options.arm =================================================================== --- head/sys/conf/options.arm (revision 290613) +++ head/sys/conf/options.arm (revision 290614) @@ -1,73 +1,74 @@ #$FreeBSD$ ARMV6 opt_global.h ARM_CACHE_LOCK_ENABLE opt_global.h ARM_INTRNG opt_global.h ARM_KERN_DIRECTMAP opt_vm.h ARM_L2_PIPT opt_global.h ARM_MANY_BOARD opt_global.h ARM_NEW_PMAP opt_global.h NKPT2PG opt_pmap.h ARM_WANT_TP_ADDRESS opt_global.h COUNTS_PER_SEC opt_timer.h CPU_ARM9 opt_global.h CPU_ARM9E opt_global.h CPU_ARM1176 opt_global.h CPU_CORTEXA opt_global.h CPU_KRAIT opt_global.h CPU_FA526 opt_global.h CPU_MV_PJ4B opt_global.h CPU_XSCALE_80219 opt_global.h CPU_XSCALE_80321 opt_global.h CPU_XSCALE_81342 opt_global.h CPU_XSCALE_IXP425 opt_global.h 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 IPI_IRQ_START opt_smp.h IPI_IRQ_END opt_smp.h FREEBSD_BOOT_LOADER opt_global.h IXP4XX_FLASH_SIZE opt_global.h KERNBASE opt_global.h KERNPHYSADDR opt_global.h KERNVIRTADDR opt_global.h LINUX_BOOT_ABI opt_global.h LOADERRAMADDR opt_global.h PHYSADDR opt_global.h PLATFORM opt_global.h SOCDEV_PA opt_global.h SOCDEV_VA opt_global.h PV_STATS opt_pmap.h QEMU_WORKAROUNDS opt_global.h SOC_BCM2835 opt_global.h SOC_BCM2836 opt_global.h SOC_IMX51 opt_global.h SOC_IMX53 opt_global.h SOC_IMX6 opt_global.h SOC_MV_ARMADAXP opt_global.h SOC_MV_DISCOVERY opt_global.h SOC_MV_DOVE opt_global.h SOC_MV_FREY opt_global.h SOC_MV_KIRKWOOD opt_global.h SOC_MV_LOKIPLUS opt_global.h SOC_MV_ORION opt_global.h SOC_OMAP3 opt_global.h SOC_OMAP4 opt_global.h SOC_TI_AM335X opt_global.h SOC_TEGRA2 opt_global.h XSCALE_CACHE_READ_WRITE_ALLOCATE opt_global.h XSACLE_DISABLE_CCNT opt_timer.h VERBOSE_INIT_ARM opt_global.h VM_MAXUSER_ADDRESS opt_global.h AT91_ATE_USE_RMII opt_at91.h AT91_MACB_USE_RMII opt_at91.h AT91_MCI_ALLOW_OVERCLOCK opt_at91.h AT91_MCI_HAS_4WIRE opt_at91.h AT91_MCI_SLOT_B opt_at91.h GFB_DEBUG opt_gfb.h GFB_NO_FONT_LOADING opt_gfb.h GFB_NO_MODE_CHANGE opt_gfb.h AT91C_MAIN_CLOCK opt_at91.h VFP opt_global.h