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