Module Name:    src
Committed By:   jmcneill
Date:           Sun Jul 15 23:47:29 UTC 2018

Added Files:
        src/sys/dev/tprof: tprof_armv7.c tprof_armv7.h

Log Message:
Add tprof backend for ARMv7 performance monitors.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/dev/tprof/tprof_armv7.c \
    src/sys/dev/tprof/tprof_armv7.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/sys/dev/tprof/tprof_armv7.c
diff -u /dev/null src/sys/dev/tprof/tprof_armv7.c:1.1
--- /dev/null	Sun Jul 15 23:47:29 2018
+++ src/sys/dev/tprof/tprof_armv7.c	Sun Jul 15 23:47:29 2018
@@ -0,0 +1,232 @@
+/* $NetBSD: tprof_armv7.c,v 1.1 2018/07/15 23:47:29 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * 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 ``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 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>
+__KERNEL_RCSID(0, "$NetBSD: tprof_armv7.c,v 1.1 2018/07/15 23:47:29 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/xcall.h>
+
+#include <dev/tprof/tprof.h>
+
+#include <arm/armreg.h>
+#include <arm/locore.h>
+
+#include <dev/tprof/tprof_armv7.h>
+
+#define	PMCR_D			__BIT(3)
+#define	PMCR_E			__BIT(0)
+
+#define	PMEVTYPER_P		__BIT(31)
+#define	PMEVTYPER_U		__BIT(30)
+#define	PMEVTYPER_EVTCOUNT	__BITS(7,0)
+
+static tprof_param_t armv7_pmu_param;
+static const u_int armv7_pmu_counter = 1;
+static uint32_t counter_val;
+static uint32_t counter_reset_val;
+
+static bool
+armv7_pmu_event_implemented(uint16_t event)
+{
+	uint32_t eid[2];
+
+	if (event >= 64)
+		return false;
+
+	eid[0] = armreg_pmceid0_read();
+	eid[1] = armreg_pmceid1_read();
+
+	const u_int idx = event / 32;
+	const u_int bit = event % 32;
+
+	if (eid[idx] & __BIT(bit))
+		return true;
+
+	return false;
+}
+
+static void
+armv7_pmu_set_pmevtyper(u_int counter, uint64_t val)
+{
+	armreg_pmselr_write(counter);
+	arm_isb();
+	armreg_pmxevtyper_write(val);
+}
+
+static void
+armv7_pmu_set_pmevcntr(u_int counter, uint32_t val)
+{
+	armreg_pmselr_write(counter);
+	arm_isb();
+	armreg_pmxevcntr_write(val);
+}
+
+static void
+armv7_pmu_start_cpu(void *arg1, void *arg2)
+{
+	const uint32_t counter_mask = __BIT(armv7_pmu_counter);
+	uint64_t pmcr, pmevtyper;
+
+	/* Enable performance monitor */
+	pmcr = armreg_pmcr_read();
+	pmcr |= PMCR_E;
+	armreg_pmcr_write(pmcr);
+
+	/* Disable event counter */
+	armreg_pmcntenclr_write(counter_mask);
+
+	/* Configure event counter */
+	pmevtyper = __SHIFTIN(armv7_pmu_param.p_event, PMEVTYPER_EVTCOUNT);
+	if (!ISSET(armv7_pmu_param.p_flags, TPROF_PARAM_USER))
+		pmevtyper |= PMEVTYPER_U;
+	if (!ISSET(armv7_pmu_param.p_flags, TPROF_PARAM_KERN))
+		pmevtyper |= PMEVTYPER_P;
+
+	armv7_pmu_set_pmevtyper(armv7_pmu_counter, pmevtyper);
+
+	/* Enable overflow interrupts */
+	armreg_pmintenset_write(counter_mask);
+
+	/* Clear overflow flag */
+	armreg_pmovsr_write(counter_mask);
+
+	/* Initialize event counter value */
+	armv7_pmu_set_pmevcntr(armv7_pmu_counter, counter_reset_val);
+
+	/* Enable event counter */
+	armreg_pmcntenset_write(counter_mask);
+}
+
+static void
+armv7_pmu_stop_cpu(void *arg1, void *arg2)
+{
+	const uint32_t counter_mask = __BIT(armv7_pmu_counter);
+	uint32_t pmcr;
+
+	/* Disable overflow interrupts */
+	armreg_pmintenclr_write(counter_mask);
+
+	/* Disable event counter */
+	armreg_pmcntenclr_write(counter_mask);
+
+	/* Disable performance monitor */
+	pmcr = armreg_pmcr_read();
+	pmcr &= ~PMCR_E;
+	armreg_pmcr_write(pmcr);
+}
+
+static uint64_t
+armv7_pmu_estimate_freq(void)
+{
+	uint64_t cpufreq = curcpu()->ci_data.cpu_cc_freq;
+	uint64_t freq = 10000;
+	uint32_t pmcr;
+
+	counter_val = cpufreq / freq;
+	if (counter_val == 0)
+		counter_val = 4000000000ULL / freq;
+
+	pmcr = armreg_pmcr_read();
+	if (pmcr & PMCR_D)
+		counter_val /= 64;
+
+	return freq;
+}
+
+static uint32_t
+armv7_pmu_ident(void)
+{
+	return TPROF_IDENT_ARMV7_GENERIC;
+}
+
+static int
+armv7_pmu_start(const tprof_param_t *param)
+{
+	uint64_t xc;
+
+	if (!armv7_pmu_event_implemented(param->p_event)) {
+		printf("%s: event 0x%#llx not implemented on this CPU\n",
+		    __func__, param->p_event);
+		return EINVAL;
+	}
+
+	counter_reset_val = -counter_val + 1;
+
+	armv7_pmu_param = *param;
+	xc = xc_broadcast(0, armv7_pmu_start_cpu, NULL, NULL);
+	xc_wait(xc);
+
+	return 0;
+}
+
+static void
+armv7_pmu_stop(const tprof_param_t *param)
+{
+	uint64_t xc;
+
+	xc = xc_broadcast(0, armv7_pmu_stop_cpu, NULL, NULL);
+	xc_wait(xc);
+}
+
+static const tprof_backend_ops_t tprof_armv7_pmu_ops = {
+	.tbo_estimate_freq = armv7_pmu_estimate_freq,
+	.tbo_ident = armv7_pmu_ident,
+	.tbo_start = armv7_pmu_start,
+	.tbo_stop = armv7_pmu_stop,
+};
+
+int
+armv7_pmu_intr(void *priv)
+{
+	const struct trapframe * const tf = priv;
+	const uint32_t counter_mask = __BIT(armv7_pmu_counter);
+	tprof_frame_info_t tfi;
+
+	const uint32_t pmovsr = armreg_pmovsr_read();
+	if ((pmovsr & counter_mask) != 0) {
+		tfi.tfi_pc = tf->tf_pc;
+		tfi.tfi_inkernel = tfi.tfi_pc >= VM_MIN_KERNEL_ADDRESS &&
+		    tfi.tfi_pc < VM_MAX_KERNEL_ADDRESS;
+		tprof_sample(NULL, &tfi);
+
+		armv7_pmu_set_pmevcntr(armv7_pmu_counter, counter_reset_val);
+	}
+	armreg_pmovsr_write(pmovsr);
+
+	return 1;
+}
+
+int
+armv7_pmu_init(void)
+{
+	return tprof_backend_register("tprof_armv7", &tprof_armv7_pmu_ops,
+	    TPROF_BACKEND_VERSION);
+}
Index: src/sys/dev/tprof/tprof_armv7.h
diff -u /dev/null src/sys/dev/tprof/tprof_armv7.h:1.1
--- /dev/null	Sun Jul 15 23:47:29 2018
+++ src/sys/dev/tprof/tprof_armv7.h	Sun Jul 15 23:47:29 2018
@@ -0,0 +1,35 @@
+/* $NetBSD: tprof_armv7.h,v 1.1 2018/07/15 23:47:29 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+#ifndef _DEV_TPROF_TPROF_ARMV7_H
+#define _DEV_TPROF_TPROF_ARMV7_H
+
+int	armv7_pmu_intr(void *);
+int	armv7_pmu_init(void);
+
+#endif /* _DEV_TPROF_TPROF_ARMV7_H */

Reply via email to