Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135941774
D1687.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D1687.diff
View Options
Index: head/lib/libpmc/libpmc.c
===================================================================
--- head/lib/libpmc/libpmc.c
+++ head/lib/libpmc/libpmc.c
@@ -74,10 +74,14 @@
static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
#endif
+#if defined(__arm__)
#if defined(__XSCALE__)
static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
#endif
+static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+#endif
#if defined(__mips__)
static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
@@ -153,6 +157,7 @@
PMC_CLASSDEP_TABLE(p5, P5);
PMC_CLASSDEP_TABLE(p6, P6);
PMC_CLASSDEP_TABLE(xscale, XSCALE);
+PMC_CLASSDEP_TABLE(armv7, ARMV7);
PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
PMC_CLASSDEP_TABLE(octeon, OCTEON);
PMC_CLASSDEP_TABLE(ucf, UCF);
@@ -286,6 +291,7 @@
PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
+PMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450);
@@ -346,9 +352,12 @@
#if defined(__i386__) || defined(__amd64__)
PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
#endif
+#if defined(__arm__)
#if defined(__XSCALE__)
PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
#endif
+PMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7);
+#endif
#if defined(__mips__)
PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
@@ -2371,6 +2380,7 @@
return (0);
}
+#if defined(__arm__)
#if defined(__XSCALE__)
static struct pmc_event_alias xscale_aliases[] = {
@@ -2394,6 +2404,25 @@
}
#endif
+static struct pmc_event_alias armv7_aliases[] = {
+ EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"),
+ EV_ALIAS("ic-misses", "L1_ICACHE_REFILL"),
+ EV_ALIAS("instructions", "INSTR_EXECUTED"),
+ EV_ALIAS(NULL, NULL)
+};
+static int
+armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
+ struct pmc_op_pmcallocate *pmc_config __unused)
+{
+ switch (pe) {
+ default:
+ break;
+ }
+
+ return (0);
+}
+#endif
+
#if defined(__mips__)
static struct pmc_event_alias mips24k_aliases[] = {
@@ -2886,6 +2915,10 @@
ev = xscale_event_table;
count = PMC_EVENT_TABLE_SIZE(xscale);
break;
+ case PMC_CLASS_ARMV7:
+ ev = armv7_event_table;
+ count = PMC_EVENT_TABLE_SIZE(armv7);
+ break;
case PMC_CLASS_MIPS24K:
ev = mips24k_event_table;
count = PMC_EVENT_TABLE_SIZE(mips24k);
@@ -3163,12 +3196,18 @@
case PMC_CPU_GENERIC:
PMC_MDEP_INIT(generic);
break;
+#if defined(__arm__)
#if defined(__XSCALE__)
case PMC_CPU_INTEL_XSCALE:
PMC_MDEP_INIT(xscale);
pmc_class_table[n] = &xscale_class_table_descr;
break;
#endif
+ case PMC_CPU_ARMV7:
+ PMC_MDEP_INIT(armv7);
+ pmc_class_table[n] = &armv7_class_table_descr;
+ break;
+#endif
#if defined(__mips__)
case PMC_CPU_MIPS_24K:
PMC_MDEP_INIT(mips24k);
@@ -3369,6 +3408,9 @@
} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
ev = xscale_event_table;
evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
+ } else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
+ ev = armv7_event_table;
+ evfence = armv7_event_table + PMC_EVENT_TABLE_SIZE(armv7);
} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
ev = mips24k_event_table;
evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
Index: head/sys/arm/arm/intr.c
===================================================================
--- head/sys/arm/arm/intr.c
+++ head/sys/arm/arm/intr.c
@@ -37,6 +37,7 @@
*/
#include "opt_platform.h"
+#include "opt_hwpmc_hooks.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -50,6 +51,8 @@
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/conf.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
#include <machine/atomic.h>
#include <machine/intr.h>
@@ -190,6 +193,10 @@
arm_mask_irq(i);
}
}
+#ifdef HWPMC_HOOKS
+ if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
+ pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, frame);
+#endif
}
/*
Index: head/sys/arm/include/pmc_mdep.h
===================================================================
--- head/sys/arm/include/pmc_mdep.h
+++ head/sys/arm/include/pmc_mdep.h
@@ -30,12 +30,15 @@
#define _MACHINE_PMC_MDEP_H_
#define PMC_MDEP_CLASS_INDEX_XSCALE 1
+#define PMC_MDEP_CLASS_INDEX_ARMV7 1
/*
* On the ARM platform we support the following PMCs.
*
* XSCALE Intel XScale processors
+ * ARMV7 ARM Cortex-A processors
*/
#include <dev/hwpmc/hwpmc_xscale.h>
+#include <dev/hwpmc/hwpmc_armv7.h>
union pmc_md_op_pmcallocate {
uint64_t __pad[4];
@@ -48,6 +51,7 @@
#ifdef _KERNEL
union pmc_md_pmc {
struct pmc_md_xscale_pmc pm_xscale;
+ struct pmc_md_armv7_pmc pm_armv7;
};
#define PMC_IN_KERNEL_STACK(S,START,END) \
@@ -73,6 +77,8 @@
*/
struct pmc_mdep *pmc_xscale_initialize(void);
void pmc_xscale_finalize(struct pmc_mdep *_md);
+struct pmc_mdep *pmc_armv7_initialize(void);
+void pmc_armv7_finalize(struct pmc_mdep *_md);
#endif /* _KERNEL */
#endif /* !_MACHINE_PMC_MDEP_H_ */
Index: head/sys/arm/ti/files.ti
===================================================================
--- head/sys/arm/ti/files.ti
+++ head/sys/arm/ti/files.ti
@@ -9,6 +9,7 @@
arm/arm/cpufunc_asm_arm10.S standard
arm/arm/cpufunc_asm_arm11.S standard
arm/arm/cpufunc_asm_armv7.S standard
+arm/arm/pmu.c optional hwpmc
arm/ti/ti_common.c standard
arm/ti/ti_cpuid.c standard
Index: head/sys/conf/files.arm
===================================================================
--- head/sys/conf/files.arm
+++ head/sys/conf/files.arm
@@ -70,6 +70,7 @@
dev/fb/fb.c optional sc
dev/fdt/fdt_arm_platform.c optional platform fdt
dev/hwpmc/hwpmc_arm.c optional hwpmc
+dev/hwpmc/hwpmc_armv7.c optional hwpmc
dev/kbd/kbd.c optional sc | vt
dev/syscons/scgfbrndr.c optional sc
dev/syscons/scterm-teken.c optional sc
Index: head/sys/dev/hwpmc/hwpmc_arm.c
===================================================================
--- head/sys/dev/hwpmc/hwpmc_arm.c
+++ head/sys/dev/hwpmc/hwpmc_arm.c
@@ -47,9 +47,12 @@
#ifdef CPU_XSCALE_IXP425
if (cpu_class == CPU_CLASS_XSCALE)
return pmc_xscale_initialize();
- else
#endif
- return NULL;
+#ifdef CPU_CORTEXA
+ if (cpu_class == CPU_CLASS_CORTEXA)
+ return pmc_armv7_initialize();
+#endif
+ return NULL;
}
void
@@ -62,6 +65,10 @@
KASSERT(0, ("[arm,%d] Unknown CPU Class 0x%x", __LINE__,
cpu_class));
#endif
+#ifdef CPU_CORTEXA
+ if (cpu_class == CPU_CLASS_CORTEXA)
+ pmc_armv7_finalize(md);
+#endif
}
int
Index: head/sys/dev/hwpmc/hwpmc_armv7.h
===================================================================
--- head/sys/dev/hwpmc/hwpmc_armv7.h
+++ head/sys/dev/hwpmc/hwpmc_armv7.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWPMC_ARMV7_H_
+#define _DEV_HWPMC_ARMV7_H_
+
+#define ARMV7_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \
+ PMC_CAP_SYSTEM | PMC_CAP_EDGE | \
+ PMC_CAP_THRESHOLD | PMC_CAP_READ | \
+ PMC_CAP_WRITE | PMC_CAP_INVERT | \
+ PMC_CAP_QUALIFIER)
+
+#define ARMV7_PMNC_ENABLE (1 << 0) /* Enable all counters */
+#define ARMV7_PMNC_P (1 << 1) /* Reset all counters */
+#define ARMV7_PMNC_C (1 << 2) /* Cycle counter reset */
+#define ARMV7_PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV7_PMNC_X (1 << 4) /* Export to ext. monitoring (ETM) */
+#define ARMV7_PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
+#define ARMV7_PMNC_N_SHIFT 11 /* Number of counters implemented */
+#define ARMV7_PMNC_N_MASK 0x1f
+#define ARMV7_PMNC_MASK 0x3f /* Writable bits */
+
+#define ARMV7_RELOAD_COUNT_TO_PERFCTR_VALUE(R) (-(R))
+#define ARMV7_PERFCTR_VALUE_TO_RELOAD_COUNT(P) (-(P))
+
+#ifdef _KERNEL
+/* MD extension for 'struct pmc' */
+struct pmc_md_armv7_pmc {
+ uint32_t pm_armv7_evsel;
+};
+#endif /* _KERNEL */
+#endif /* _DEV_HWPMC_ARMV7_H_ */
Index: head/sys/dev/hwpmc/hwpmc_armv7.c
===================================================================
--- head/sys/dev/hwpmc/hwpmc_armv7.c
+++ head/sys/dev/hwpmc/hwpmc_armv7.c
@@ -0,0 +1,652 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+
+#include <machine/pmc_mdep.h>
+#include <machine/cpu.h>
+
+#define CPU_ID_CORTEX_VER_MASK 0xff
+#define CPU_ID_CORTEX_VER_SHIFT 4
+
+static int armv7_npmcs;
+
+struct armv7_event_code_map {
+ enum pmc_event pe_ev;
+ uint8_t pe_code;
+};
+
+const struct armv7_event_code_map armv7_event_codes[] = {
+ { PMC_EV_ARMV7_PMNC_SW_INCR, 0x00 },
+ { PMC_EV_ARMV7_L1_ICACHE_REFILL, 0x01 },
+ { PMC_EV_ARMV7_ITLB_REFILL, 0x02 },
+ { PMC_EV_ARMV7_L1_DCACHE_REFILL, 0x03 },
+ { PMC_EV_ARMV7_L1_DCACHE_ACCESS, 0x04 },
+ { PMC_EV_ARMV7_DTLB_REFILL, 0x05 },
+ { PMC_EV_ARMV7_MEM_READ, 0x06 },
+ { PMC_EV_ARMV7_MEM_WRITE, 0x07 },
+ { PMC_EV_ARMV7_INSTR_EXECUTED, 0x08 },
+ { PMC_EV_ARMV7_EXC_TAKEN, 0x09 },
+ { PMC_EV_ARMV7_EXC_EXECUTED, 0x0A },
+ { PMC_EV_ARMV7_CID_WRITE, 0x0B },
+ { PMC_EV_ARMV7_PC_WRITE, 0x0C },
+ { PMC_EV_ARMV7_PC_IMM_BRANCH, 0x0D },
+ { PMC_EV_ARMV7_PC_PROC_RETURN, 0x0E },
+ { PMC_EV_ARMV7_MEM_UNALIGNED_ACCESS, 0x0F },
+ { PMC_EV_ARMV7_PC_BRANCH_MIS_PRED, 0x10 },
+ { PMC_EV_ARMV7_CLOCK_CYCLES, 0x11 },
+ { PMC_EV_ARMV7_PC_BRANCH_PRED, 0x12 },
+ { PMC_EV_ARMV7_MEM_ACCESS, 0x13 },
+ { PMC_EV_ARMV7_L1_ICACHE_ACCESS, 0x14 },
+ { PMC_EV_ARMV7_L1_DCACHE_WB, 0x15 },
+ { PMC_EV_ARMV7_L2_CACHE_ACCESS, 0x16 },
+ { PMC_EV_ARMV7_L2_CACHE_REFILL, 0x17 },
+ { PMC_EV_ARMV7_L2_CACHE_WB, 0x18 },
+ { PMC_EV_ARMV7_BUS_ACCESS, 0x19 },
+ { PMC_EV_ARMV7_MEM_ERROR, 0x1A },
+ { PMC_EV_ARMV7_INSTR_SPEC, 0x1B },
+ { PMC_EV_ARMV7_TTBR_WRITE, 0x1C },
+ { PMC_EV_ARMV7_BUS_CYCLES, 0x1D },
+ { PMC_EV_ARMV7_CPU_CYCLES, 0xFF },
+};
+
+const int armv7_event_codes_size =
+ sizeof(armv7_event_codes) / sizeof(armv7_event_codes[0]);
+
+/*
+ * Per-processor information.
+ */
+struct armv7_cpu {
+ struct pmc_hw *pc_armv7pmcs;
+ int cortex_ver;
+};
+
+static struct armv7_cpu **armv7_pcpu;
+
+/*
+ * Performance Monitor Control Register
+ */
+static __inline uint32_t
+armv7_pmnc_read(void)
+{
+ uint32_t reg;
+
+ __asm __volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (reg));
+
+ return (reg);
+}
+
+static __inline void
+armv7_pmnc_write(uint32_t reg)
+{
+
+ __asm __volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (reg));
+}
+
+/*
+ * Clock Counter Register (PMCCNTR)
+ * Counts processor clock cycles.
+ */
+static __inline uint32_t
+armv7_ccnt_read(void)
+{
+ uint32_t reg;
+
+ __asm __volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (reg));
+
+ return (reg);
+}
+
+static __inline void
+armv7_ccnt_write(uint32_t reg)
+{
+
+ __asm __volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (reg));
+}
+
+/*
+ * Interrupt Enable Set Register
+ */
+static __inline void
+armv7_interrupt_enable(uint32_t pmc)
+{
+ uint32_t reg;
+
+ reg = (1 << pmc);
+
+ __asm __volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (reg));
+}
+
+/*
+ * Interrupt Clear Set Register
+ */
+static __inline void
+armv7_interrupt_disable(uint32_t pmc)
+{
+ uint32_t reg;
+
+ reg = (1 << pmc);
+
+ __asm __volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (reg));
+}
+
+/*
+ * Overflow Flag Register
+ */
+static __inline uint32_t
+armv7_flag_read(void)
+{
+ uint32_t reg;
+
+ __asm __volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (reg));
+
+ return (reg);
+}
+
+static __inline void
+armv7_flag_write(uint32_t reg)
+{
+
+ __asm __volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (reg));
+}
+
+/*
+ * Event Selection Register
+ */
+static __inline void
+armv7_evtsel_write(uint32_t reg)
+{
+
+ __asm __volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (reg));
+}
+
+/*
+ * PMSELR
+ */
+static __inline void
+armv7_select_counter(unsigned int pmc)
+{
+
+ __asm __volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (pmc));
+}
+
+/*
+ * Counter Set Enable Register
+ */
+static __inline void
+armv7_counter_enable(unsigned int pmc)
+{
+ uint32_t reg;
+
+ reg = (1 << pmc);
+
+ __asm __volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (reg));
+}
+
+/*
+ * Counter Clear Enable Register
+ */
+static __inline void
+armv7_counter_disable(unsigned int pmc)
+{
+ uint32_t reg;
+
+ reg = (1 << pmc);
+
+ __asm __volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (reg));
+}
+
+/*
+ * Performance Count Register N
+ */
+static uint32_t
+armv7_pmcn_read(unsigned int pmc)
+{
+ uint32_t reg = 0;
+
+ KASSERT(pmc < 4, ("[armv7,%d] illegal PMC number %d", __LINE__, pmc));
+
+ armv7_select_counter(pmc);
+ __asm __volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (reg));
+
+ return (reg);
+}
+
+static uint32_t
+armv7_pmcn_write(unsigned int pmc, uint32_t reg)
+{
+
+ KASSERT(pmc < 4, ("[armv7,%d] illegal PMC number %d", __LINE__, pmc));
+
+ armv7_select_counter(pmc);
+ __asm __volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (reg));
+
+ return (reg);
+}
+
+static int
+armv7_allocate_pmc(int cpu, int ri, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ uint32_t caps, config;
+ struct armv7_cpu *pac;
+ enum pmc_event pe;
+ int i;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] illegal row index %d", __LINE__, ri));
+
+ pac = armv7_pcpu[cpu];
+
+ caps = a->pm_caps;
+ if (a->pm_class != PMC_CLASS_ARMV7)
+ return (EINVAL);
+ pe = a->pm_ev;
+
+ for (i = 0; i < armv7_event_codes_size; i++) {
+ if (armv7_event_codes[i].pe_ev == pe) {
+ config = armv7_event_codes[i].pe_code;
+ break;
+ }
+ }
+ if (i == armv7_event_codes_size)
+ return EINVAL;
+
+ pm->pm_md.pm_armv7.pm_armv7_evsel = config;
+
+ PMCDBG(MDP,ALL,2,"armv7-allocate ri=%d -> config=0x%x", ri, config);
+
+ return 0;
+}
+
+
+static int
+armv7_read_pmc(int cpu, int ri, pmc_value_t *v)
+{
+ pmc_value_t tmp;
+ struct pmc *pm;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] illegal row index %d", __LINE__, ri));
+
+ pm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
+
+ if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
+ tmp = armv7_ccnt_read();
+ else
+ tmp = armv7_pmcn_read(ri);
+
+ PMCDBG(MDP,REA,2,"armv7-read id=%d -> %jd", ri, tmp);
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ *v = ARMV7_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
+ else
+ *v = tmp;
+
+ return 0;
+}
+
+static int
+armv7_write_pmc(int cpu, int ri, pmc_value_t v)
+{
+ struct pmc *pm;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] illegal row-index %d", __LINE__, ri));
+
+ pm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
+
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ v = ARMV7_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
+
+ PMCDBG(MDP,WRI,1,"armv7-write cpu=%d ri=%d v=%jx", cpu, ri, v);
+
+ if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
+ armv7_ccnt_write(v);
+ else
+ armv7_pmcn_write(ri, v);
+
+ return 0;
+}
+
+static int
+armv7_config_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pmc_hw *phw;
+
+ PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
+
+ KASSERT(pm == NULL || phw->phw_pmc == NULL,
+ ("[armv7,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
+ __LINE__, pm, phw->phw_pmc));
+
+ phw->phw_pmc = pm;
+
+ return 0;
+}
+
+static int
+armv7_start_pmc(int cpu, int ri)
+{
+ struct pmc_hw *phw;
+ uint32_t config;
+ struct pmc *pm;
+
+ phw = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
+ pm = phw->phw_pmc;
+ config = pm->pm_md.pm_armv7.pm_armv7_evsel;
+
+ /*
+ * Configure the event selection.
+ */
+ armv7_select_counter(ri);
+ armv7_evtsel_write(config);
+
+ /*
+ * Enable the PMC.
+ */
+ armv7_interrupt_enable(ri);
+ armv7_counter_enable(ri);
+
+ return 0;
+}
+
+static int
+armv7_stop_pmc(int cpu, int ri)
+{
+ struct pmc_hw *phw;
+ struct pmc *pm;
+
+ phw = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
+ pm = phw->phw_pmc;
+
+ /*
+ * Disable the PMCs.
+ */
+ armv7_counter_disable(ri);
+ armv7_interrupt_disable(ri);
+
+ return 0;
+}
+
+static int
+armv7_release_pmc(int cpu, int ri, struct pmc *pmc)
+{
+ struct pmc_hw *phw;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
+ KASSERT(phw->phw_pmc == NULL,
+ ("[armv7,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
+
+ return 0;
+}
+
+static int
+armv7_intr(int cpu, struct trapframe *tf)
+{
+ struct armv7_cpu *pc;
+ int retval, ri;
+ struct pmc *pm;
+ int error;
+ int reg;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] CPU %d out of range", __LINE__, cpu));
+
+ retval = 0;
+ pc = armv7_pcpu[cpu];
+
+ for (ri = 0; ri < armv7_npmcs; ri++) {
+ pm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
+ if (pm == NULL)
+ continue;
+ if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ continue;
+
+ /* Check if counter has overflowed */
+ if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
+ reg = (1 << 31);
+ else
+ reg = (1 << ri);
+
+ if ((armv7_flag_read() & reg) == 0) {
+ continue;
+ }
+
+ /* Clear Overflow Flag */
+ armv7_flag_write(reg);
+
+ retval = 1; /* Found an interrupting PMC. */
+ if (pm->pm_state != PMC_STATE_RUNNING)
+ continue;
+
+ error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
+ TRAPF_USERMODE(tf));
+ if (error)
+ armv7_stop_pmc(cpu, ri);
+
+ /* Reload sampling count */
+ armv7_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount);
+ }
+
+ return (retval);
+}
+
+static int
+armv7_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
+{
+ char armv7_name[PMC_NAME_MAX];
+ struct pmc_hw *phw;
+ int error;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d], illegal CPU %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < armv7_npmcs,
+ ("[armv7,%d] row-index %d out of range", __LINE__, ri));
+
+ phw = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
+ snprintf(armv7_name, sizeof(armv7_name), "ARMV7-%d", ri);
+ if ((error = copystr(armv7_name, pi->pm_name, PMC_NAME_MAX,
+ NULL)) != 0)
+ return error;
+ pi->pm_class = PMC_CLASS_ARMV7;
+ if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
+ pi->pm_enabled = TRUE;
+ *ppmc = phw->phw_pmc;
+ } else {
+ pi->pm_enabled = FALSE;
+ *ppmc = NULL;
+ }
+
+ return (0);
+}
+
+static int
+armv7_get_config(int cpu, int ri, struct pmc **ppm)
+{
+
+ *ppm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
+
+ return 0;
+}
+
+/*
+ * XXX don't know what we should do here.
+ */
+static int
+armv7_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
+{
+
+ return 0;
+}
+
+static int
+armv7_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
+{
+
+ return 0;
+}
+
+static int
+armv7_pcpu_init(struct pmc_mdep *md, int cpu)
+{
+ struct armv7_cpu *pac;
+ struct pmc_hw *phw;
+ struct pmc_cpu *pc;
+ uint32_t pmnc;
+ int first_ri;
+ int cpuid;
+ int i;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[armv7,%d] wrong cpu number %d", __LINE__, cpu));
+ PMCDBG(MDP,INI,1,"armv7-init cpu=%d", cpu);
+
+ armv7_pcpu[cpu] = pac = malloc(sizeof(struct armv7_cpu), M_PMC,
+ M_WAITOK|M_ZERO);
+
+ cpuid = cpu_id();
+ pac->cortex_ver = (cpuid >> CPU_ID_CORTEX_VER_SHIFT) & \
+ CPU_ID_CORTEX_VER_MASK;
+
+ pac->pc_armv7pmcs = malloc(sizeof(struct pmc_hw) * armv7_npmcs,
+ M_PMC, M_WAITOK|M_ZERO);
+ pc = pmc_pcpu[cpu];
+ first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_ARMV7].pcd_ri;
+ KASSERT(pc != NULL, ("[armv7,%d] NULL per-cpu pointer", __LINE__));
+
+ for (i = 0, phw = pac->pc_armv7pmcs; i < armv7_npmcs; i++, phw++) {
+ phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
+ PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
+ phw->phw_pmc = NULL;
+ pc->pc_hwpmcs[i + first_ri] = phw;
+ }
+
+ /* Enable unit */
+ pmnc = armv7_pmnc_read();
+ pmnc |= ARMV7_PMNC_ENABLE;
+ armv7_pmnc_write(pmnc);
+
+ return 0;
+}
+
+static int
+armv7_pcpu_fini(struct pmc_mdep *md, int cpu)
+{
+ uint32_t pmnc;
+
+ pmnc = armv7_pmnc_read();
+ pmnc &= ~ARMV7_PMNC_ENABLE;
+ armv7_pmnc_write(pmnc);
+
+ return 0;
+}
+
+struct pmc_mdep *
+pmc_armv7_initialize()
+{
+ struct pmc_mdep *pmc_mdep;
+ struct pmc_classdep *pcd;
+ int reg;
+
+ reg = armv7_pmnc_read();
+
+ armv7_npmcs = (reg >> ARMV7_PMNC_N_SHIFT) & \
+ ARMV7_PMNC_N_MASK;
+
+ PMCDBG(MDP,INI,1,"armv7-init npmcs=%d", armv7_npmcs);
+
+ /*
+ * Allocate space for pointers to PMC HW descriptors and for
+ * the MDEP structure used by MI code.
+ */
+ armv7_pcpu = malloc(sizeof(struct armv7_cpu *) * pmc_cpu_max(),
+ M_PMC, M_WAITOK | M_ZERO);
+
+ /* Just one class */
+ pmc_mdep = pmc_mdep_alloc(1);
+ pmc_mdep->pmd_cputype = PMC_CPU_ARMV7;
+
+ pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_ARMV7];
+ pcd->pcd_caps = ARMV7_PMC_CAPS;
+ pcd->pcd_class = PMC_CLASS_ARMV7;
+ pcd->pcd_num = armv7_npmcs;
+ pcd->pcd_ri = pmc_mdep->pmd_npmc;
+ pcd->pcd_width = 32;
+
+ pcd->pcd_allocate_pmc = armv7_allocate_pmc;
+ pcd->pcd_config_pmc = armv7_config_pmc;
+ pcd->pcd_pcpu_fini = armv7_pcpu_fini;
+ pcd->pcd_pcpu_init = armv7_pcpu_init;
+ pcd->pcd_describe = armv7_describe;
+ pcd->pcd_get_config = armv7_get_config;
+ pcd->pcd_read_pmc = armv7_read_pmc;
+ pcd->pcd_release_pmc = armv7_release_pmc;
+ pcd->pcd_start_pmc = armv7_start_pmc;
+ pcd->pcd_stop_pmc = armv7_stop_pmc;
+ pcd->pcd_write_pmc = armv7_write_pmc;
+
+ pmc_mdep->pmd_intr = armv7_intr;
+ pmc_mdep->pmd_switch_in = armv7_switch_in;
+ pmc_mdep->pmd_switch_out = armv7_switch_out;
+
+ pmc_mdep->pmd_npmc += armv7_npmcs;
+
+ return (pmc_mdep);
+}
+
+void
+pmc_armv7_finalize(struct pmc_mdep *md)
+{
+
+}
Index: head/sys/dev/hwpmc/pmc_events.h
===================================================================
--- head/sys/dev/hwpmc/pmc_events.h
+++ head/sys/dev/hwpmc/pmc_events.h
@@ -4757,6 +4757,46 @@
#define PMC_EV_XSCALE_LAST PMC_EV_XSCALE_DATA_BUS_TRANS
/*
+ * ARMv7 Events
+ */
+
+#define __PMC_EV_ARMV7() \
+ __PMC_EV(ARMV7, PMNC_SW_INCR) \
+ __PMC_EV(ARMV7, L1_ICACHE_REFILL) \
+ __PMC_EV(ARMV7, ITLB_REFILL) \
+ __PMC_EV(ARMV7, L1_DCACHE_REFILL) \
+ __PMC_EV(ARMV7, L1_DCACHE_ACCESS) \
+ __PMC_EV(ARMV7, DTLB_REFILL) \
+ __PMC_EV(ARMV7, MEM_READ) \
+ __PMC_EV(ARMV7, MEM_WRITE) \
+ __PMC_EV(ARMV7, INSTR_EXECUTED) \
+ __PMC_EV(ARMV7, EXC_TAKEN) \
+ __PMC_EV(ARMV7, EXC_EXECUTED) \
+ __PMC_EV(ARMV7, CID_WRITE) \
+ __PMC_EV(ARMV7, PC_WRITE) \
+ __PMC_EV(ARMV7, PC_IMM_BRANCH) \
+ __PMC_EV(ARMV7, PC_PROC_RETURN) \
+ __PMC_EV(ARMV7, MEM_UNALIGNED_ACCESS) \
+ __PMC_EV(ARMV7, PC_BRANCH_MIS_PRED) \
+ __PMC_EV(ARMV7, CLOCK_CYCLES) \
+ __PMC_EV(ARMV7, PC_BRANCH_PRED) \
+ __PMC_EV(ARMV7, MEM_ACCESS) \
+ __PMC_EV(ARMV7, L1_ICACHE_ACCESS) \
+ __PMC_EV(ARMV7, L1_DCACHE_WB) \
+ __PMC_EV(ARMV7, L2_CACHE_ACCESS) \
+ __PMC_EV(ARMV7, L2_CACHE_REFILL) \
+ __PMC_EV(ARMV7, L2_CACHE_WB) \
+ __PMC_EV(ARMV7, BUS_ACCESS) \
+ __PMC_EV(ARMV7, MEM_ERROR) \
+ __PMC_EV(ARMV7, INSTR_SPEC) \
+ __PMC_EV(ARMV7, TTBR_WRITE) \
+ __PMC_EV(ARMV7, BUS_CYCLES) \
+ __PMC_EV(ARMV7, CPU_CYCLES)
+
+#define PMC_EV_ARMV7_FIRST PMC_EV_ARMV7_PMNC_SW_INCR
+#define PMC_EV_ARMV7_LAST PMC_EV_ARMV7_CPU_CYCLES
+
+/*
* MIPS Events from "Programming the MIPS32 24K Core Family",
* Document Number: MD00355 Revision 04.63 December 19, 2008
* These events are kept in the order found in Table 7.4.
@@ -5219,7 +5259,8 @@
* 0x11080 0x0080 INTEL Pentium MMX events
* 0x11100 0x0100 INTEL Pentium Pro/P-II/P-III/Pentium-M events
* 0x11200 0x00FF INTEL XScale events
- * 0x11300 0x00FF MIPS 24K events
+ * 0x11300 0x00FF MIPS 24K events
+ * 0x14000 0x0100 ARMv7 events
* 0x20000 0x1000 Software events
*/
#define __PMC_EVENTS() \
@@ -5253,6 +5294,8 @@
__PMC_EV_PPC7450() \
__PMC_EV_BLOCK(PPC970, 0x13100) \
__PMC_EV_PPC970() \
+ __PMC_EV_BLOCK(ARMV7, 0x14000) \
+ __PMC_EV_ARMV7() \
#define PMC_EVENT_FIRST PMC_EV_TSC_TSC
#define PMC_EVENT_LAST PMC_EV_SOFT_LAST
Index: head/sys/sys/pmc.h
===================================================================
--- head/sys/sys/pmc.h
+++ head/sys/sys/pmc.h
@@ -73,6 +73,7 @@
#define __PMC_CPUS() \
__PMC_CPU(AMD_K7, 0x00, "AMD K7") \
__PMC_CPU(AMD_K8, 0x01, "AMD K8") \
+ __PMC_CPU(ARMV7, 0x500, "ARMv7") \
__PMC_CPU(INTEL_P5, 0x80, "Intel Pentium") \
__PMC_CPU(INTEL_P6, 0x81, "Intel Pentium Pro") \
__PMC_CPU(INTEL_CL, 0x82, "Intel Celeron") \
@@ -127,6 +128,7 @@
__PMC_CLASS(UCF) /* Intel Uncore fixed function */ \
__PMC_CLASS(UCP) /* Intel Uncore programmable */ \
__PMC_CLASS(XSCALE) /* Intel XScale counters */ \
+ __PMC_CLASS(ARMV7) /* ARMv7 */ \
__PMC_CLASS(MIPS24K) /* MIPS 24K */ \
__PMC_CLASS(OCTEON) /* Cavium Octeon */ \
__PMC_CLASS(PPC7450) /* Motorola MPC7450 class */ \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 15, 9:38 AM (8 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25322759
Default Alt Text
D1687.diff (28 KB)
Attached To
Mode
D1687: ARMv7 counters
Attached
Detach File
Event Timeline
Log In to Comment